home *** CD-ROM | disk | FTP | other *** search
/ PC World Komputer 2010 April / PCWorld0410.iso / hity wydania / Ubuntu 9.10 PL / karmelkowy-koliberek-desktop-9.10-i386-PL.iso / casper / filesystem.squashfs / usr / bin / ckbcomp < prev    next >
Text File  |  2009-10-02  |  116KB  |  3,895 lines

  1. #!/usr/bin/perl
  2.  
  3. #     ckbcomp -- compile XKB keyboard definitions to loadkeys format
  4. #     Copyright ┬⌐ 2005,2006 Anton Zinoviev <anton@lml.bas.bg>
  5.  
  6. #     This program is free software; you can redistribute it and/or modify
  7. #     it under the terms of the GNU General Public License as published by
  8. #     the Free Software Foundation; either version 2 of the License, or
  9. #     (at your option) any later version.
  10.  
  11. #     This program is distributed in the hope that it will be useful,
  12. #     but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. #     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14. #     GNU General Public License for more details.
  15.  
  16. #     If you have not received a copy of the GNU General Public License
  17. #     along with this program, write to the Free Software Foundation, Inc.,
  18. #     59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  19.  
  20. use warnings 'all';
  21. use strict;
  22. use locale;
  23.  
  24. my $debug_flag = 1;
  25. sub debug {
  26.     if ($debug_flag) {
  27.     print STDERR "@_";
  28.     }
  29. }
  30.  
  31. sub warning {
  32.     print STDERR  "WARNING: @_";
  33. }
  34.  
  35. ########### ARGUMENTS ###############################################
  36.  
  37. my $charmap;
  38. my $acm;
  39.  
  40. my $verbosity = 0;
  41.  
  42. my @xdirs = ('/etc/console-setup/ckb',
  43.          '/usr/share/X11/xkb',
  44.          '/etc/X11/xkb',
  45.          '/usr/X11R6/lib/X11/xkb');
  46.  
  47. my $keycodes;
  48. my $symbols;
  49.  
  50. my $rules;
  51. my $model;
  52. my @layouts;
  53. my @variants = ();
  54. my @options = ();
  55. my $compact = 0;
  56.  
  57. while (@ARGV) {
  58.     $_ = shift @ARGV;
  59.     if (s/^-//) {
  60.     if (/^charmap$/) {
  61.         if ($charmap) {
  62.         die "$0: No more than one -charmap option is allowed\n";
  63.         }
  64.         $charmap = $ARGV[0];
  65.         shift @ARGV;
  66.     } elsif (/^v(erbose)?$/) {
  67.         if ($verbosity) {
  68.         die "$0: No more than one -verbose option is allowed\n";
  69.         }
  70.         if ($ARGV[0] =~ /^[0-9]|10$/) {
  71.         $verbosity = $ARGV[0];
  72.         shift @ARGV;
  73.         } else {
  74.         $verbosity = 5;
  75.         }
  76.     } elsif (/^I(.*)$/) {
  77.         @xdirs = ($1, @xdirs);
  78.     } elsif (/^keycodes$/) {
  79.         if ($keycodes) {
  80.         die "$0: No more than one -keycodes option is allowed\n";
  81.         }
  82.         $keycodes = $ARGV[0];
  83.         shift @ARGV;
  84.     } elsif (/^symbols$/) {
  85.         if ($symbols) {
  86.         die "$0: No more than one -symbols option is allowed\n";
  87.         }
  88.         $symbols = $ARGV[0];
  89.         shift @ARGV;
  90.     } elsif (/^rules$/) {
  91.         if ($rules) {
  92.         die "$0: No more than one -rules option is allowed\n";
  93.         }
  94.         $rules = $ARGV[0];
  95.         shift @ARGV;
  96.     } elsif (/^model$/) {
  97.         if ($model) {
  98.         die "$0: No more than one -model option is allowed\n";
  99.         }
  100.         $model = $ARGV[0];
  101.         $model =~ s/[[:space:]]//g;
  102.         shift @ARGV;
  103.     } elsif (/^layout$/) {
  104.         if (@layouts) {
  105.         die "$0: No more than one -layout option is allowed\n";
  106.         }
  107.         $ARGV[0] =~ s/[[:space:]]//g;
  108.         @layouts = split (/,/, $ARGV[0], -1);
  109.         shift @ARGV;
  110.     } elsif (/^variant$/) {
  111.         if (@variants) {
  112.         die "$0: No more than one -variant option is allowed\n";
  113.         }
  114.         $ARGV[0] =~ s/[[:space:]]//g;
  115.         @variants = split (/,/, $ARGV[0], -1);
  116.         shift @ARGV;
  117.     } elsif (/^option$/) {
  118.         $ARGV[0] =~ s/[[:space:]]//g;
  119.         @options = (@options, split (/,/, $ARGV[0], -1));
  120.         shift @ARGV;
  121.     } elsif (/^help$|^-help$|^\?$/) {
  122.         print <<EOT;
  123. Usage: ckbcomp [args] [<layout> [<variant> [<option> ... ]]]
  124. Where legal args are:
  125. -?,-help            Print this message
  126. -charmap <name>     Specifies the encoding to use
  127. -I<dir>             Add <dir> to list of directories to be used
  128. -keycodes <name>    Specifies keycodes component name
  129. -symbols <name>     Specifies symbols component name
  130. -rules <name>       Name of rules file to use
  131. -model <name>       Specifies model used to choose component names
  132. -layout <name>      Specifies layout used to choose component names
  133. -variant <name>     Specifies layout variant used to choose component names
  134. -option <name>      Adds an option used to choose component names
  135. -v[erbose] [<lvl>]  Sets verbosity (1..10).  Higher values yield
  136.                     more messages
  137. -compact            Generate compact keymap
  138. EOT
  139.             exit 0;
  140.     } elsif (/^compact$/) {
  141.         $compact = 1;
  142.     } else {
  143.         die "$0: Unknown option -$_\n";
  144.     }
  145.     } else {
  146.     if (! @layouts) {
  147.         $_ =~ s/[[:space:]]//g;
  148.         @layouts = split (/,/, $_, -1);
  149.     } elsif (! @variants) {
  150.         $_ =~ s/[[:space:]]//g;
  151.         @variants = split (/,/, $_, -1);
  152.         @variants = ('') if (! @variants);
  153.     } else {
  154.         $_ =~ s/[[:space:]]//g;
  155.         @options = (@options, split (/,/, $_, -1));
  156.     }
  157.     }
  158. }
  159.  
  160. $rules = 'xorg' if (! $rules);
  161. $model = 'pc104' if (! $model);
  162.  
  163. ########### GLOBAL VARIABLES #########################################
  164.  
  165. my %rules_variables = (); # The variables defined in the rules file
  166.  
  167. my $arch = 'at'; # The name of a mapping between X key codes and kernel
  168.                  # keycodes
  169.  
  170. my %acmtable; # Unicode -> legacy code (defined only when -charmap is given)
  171.  
  172. my $KEYMAP = ''; # This variable contains the generated keymap
  173.  
  174. my $broken_caps = 0; # In unicode mode Caps_Lock doesn't work for non-ASCII
  175.                      # letters.  1 = the keymap contains non-ascii letters.
  176.                      # See http://bugzilla.kernel.org/show_bug.cgi?id=7746#c21
  177.  
  178. my %keycodes_table; # x keysym -> x key code
  179. my %aliases;        # x keysym -> x keysym
  180.  
  181. my %symbols_table;   # x key code -> [[symbols for group0,...],
  182.                      #                [symbols for group1,...], ...]
  183. my %types_table;     # x key code -> key type (i.e. "TWO_LEVEL")
  184.  
  185. my $augment_method = 1;   # Constants for different XKB include methods
  186. my $override_method = 2;
  187. my $replace_method = 3;
  188. my $alternate_method = 4;
  189. my $ignore_method = 5;    # This is not a XKB method and means "don't include"
  190.  
  191. my $filename;       # The name of the currently read file
  192. my $stream = '';    # The contents of $filename that still has not been parsed
  193. my $method = $override_method; # The current method (by default "override")
  194. my $base_group = 0; # The base group to include in (for "symbols" files only)
  195.  
  196. my %kernel_modifiers = ('Shift' => 0x01,
  197.             'Shift_Lock' => 0x01,
  198.             'AltGr' => 0x02,
  199.             'AltGr_Lock' => 0x02,
  200.             'Control' => 0x04,
  201.             'Control_Lock' => 0x04,
  202.             'Alt' => 0x08,
  203.             'Alt_Lock' => 0x08,
  204.             'ShiftL' => 0x10,
  205.             'ShiftL_Lock' => 0x10,
  206.             'ShiftR' => 0x20,
  207.             'ShiftR_Lock' => 0x20,
  208.             'CtrlL' => 0x40,
  209.             'CtrlL_Lock' => 0x40,
  210.             'CtrlR' => 0x80,
  211.             'CtrlR_Lock' => 0x80);
  212.  
  213. my @modifier_combinations = ('plain',
  214.                              'shift',
  215.                              'altgr',
  216.                              'altgr shift',
  217.                              'control',
  218.                              'control shift',
  219.                              'control altgr',
  220.                              'control altgr shift',
  221.                              'alt',
  222.                              'alt shift',
  223.                              'alt altgr',
  224.                              'alt altgr shift',
  225.                              'alt control',
  226.                              'alt control shift',
  227.                              'alt control altgr',
  228.                              'alt control altgr shift',
  229.                              'shiftl',
  230.                              'shiftl shift',
  231.                              'shiftl altgr',
  232.                              'shiftl altgr shift',
  233.                              'shiftl control',
  234.                              'shiftl control shift',
  235.                              'shiftl control altgr',
  236.                              'shiftl control altgr shift',
  237.                              'shiftl alt',
  238.                              'shiftl alt shift',
  239.                              'shiftl alt altgr',
  240.                              'shiftl alt altgr shift',
  241.                              'shiftl alt control',
  242.                              'shiftl alt control shift',
  243.                              'shiftl alt control altgr',
  244.                              'shiftl alt control altgr shift',
  245.                              'shiftr',
  246.                              'shiftr shift',
  247.                              'shiftr altgr',
  248.                              'shiftr altgr shift',
  249.                              'shiftr control',
  250.                              'shiftr control shift',
  251.                              'shiftr control altgr',
  252.                              'shiftr control altgr shift',
  253.                              'shiftr alt',
  254.                              'shiftr alt shift',
  255.                              'shiftr alt altgr',
  256.                              'shiftr alt altgr shift',
  257.                              'shiftr alt control',
  258.                              'shiftr alt control shift',
  259.                              'shiftr alt control altgr',
  260.                              'shiftr alt control altgr shift',
  261.                              'shiftr shiftl',
  262.                              'shiftr shiftl shift',
  263.                              'shiftr shiftl altgr',
  264.                              'shiftr shiftl altgr shift',
  265.                              'shiftr shiftl control',
  266.                              'shiftr shiftl control shift',
  267.                              'shiftr shiftl control altgr',
  268.                              'shiftr shiftl control altgr shift',
  269.                              'shiftr shiftl alt',
  270.                              'shiftr shiftl alt shift',
  271.                              'shiftr shiftl alt altgr',
  272.                              'shiftr shiftl alt altgr shift',
  273.                              'shiftr shiftl alt control',
  274.                              'shiftr shiftl alt control shift',
  275.                              'shiftr shiftl alt control altgr',
  276.                              'shiftr shiftl alt control altgr shift',
  277.                              'ctrll',
  278.                              'ctrll shift',
  279.                              'ctrll altgr',
  280.                              'ctrll altgr shift',
  281.                              'ctrll control',
  282.                              'ctrll control shift',
  283.                              'ctrll control altgr',
  284.                              'ctrll control altgr shift',
  285.                              'ctrll alt',
  286.                              'ctrll alt shift',
  287.                              'ctrll alt altgr',
  288.                              'ctrll alt altgr shift',
  289.                              'ctrll alt control',
  290.                              'ctrll alt control shift',
  291.                              'ctrll alt control altgr',
  292.                              'ctrll alt control altgr shift',
  293.                              'ctrll shiftl',
  294.                              'ctrll shiftl shift',
  295.                              'ctrll shiftl altgr',
  296.                              'ctrll shiftl altgr shift',
  297.                              'ctrll shiftl control',
  298.                              'ctrll shiftl control shift',
  299.                              'ctrll shiftl control altgr',
  300.                              'ctrll shiftl control altgr shift',
  301.                              'ctrll shiftl alt',
  302.                              'ctrll shiftl alt shift',
  303.                              'ctrll shiftl alt altgr',
  304.                              'ctrll shiftl alt altgr shift',
  305.                              'ctrll shiftl alt control',
  306.                              'ctrll shiftl alt control shift',
  307.                              'ctrll shiftl alt control altgr',
  308.                              'ctrll shiftl alt control altgr shift',
  309.                              'ctrll shiftr',
  310.                              'ctrll shiftr shift',
  311.                              'ctrll shiftr altgr',
  312.                              'ctrll shiftr altgr shift',
  313.                              'ctrll shiftr control',
  314.                              'ctrll shiftr control shift',
  315.                              'ctrll shiftr control altgr',
  316.                              'ctrll shiftr control altgr shift',
  317.                              'ctrll shiftr alt',
  318.                              'ctrll shiftr alt shift',
  319.                              'ctrll shiftr alt altgr',
  320.                              'ctrll shiftr alt altgr shift',
  321.                              'ctrll shiftr alt control',
  322.                              'ctrll shiftr alt control shift',
  323.                              'ctrll shiftr alt control altgr',
  324.                              'ctrll shiftr alt control altgr shift',
  325.                              'ctrll shiftr shiftl',
  326.                              'ctrll shiftr shiftl shift',
  327.                              'ctrll shiftr shiftl altgr',
  328.                              'ctrll shiftr shiftl altgr shift',
  329.                              'ctrll shiftr shiftl control',
  330.                              'ctrll shiftr shiftl control shift',
  331.                              'ctrll shiftr shiftl control altgr',
  332.                              'ctrll shiftr shiftl control altgr shift',
  333.                              'ctrll shiftr shiftl alt',
  334.                              'ctrll shiftr shiftl alt shift',
  335.                              'ctrll shiftr shiftl alt altgr',
  336.                              'ctrll shiftr shiftl alt altgr shift',
  337.                              'ctrll shiftr shiftl alt control',
  338.                              'ctrll shiftr shiftl alt control shift',
  339.                              'ctrll shiftr shiftl alt control altgr',
  340.                              'ctrll shiftr shiftl alt control altgr shift',
  341.                 );
  342.  
  343. # Some Unicodes cause the kernel/loadkeys to issue "Segmentation fault"
  344. # kbd 1.15-1 (deliberately) fails on anything in the range 0xf000..0xffff;
  345. # see http://bugs.debian.org/500116.
  346. my %forbidden;
  347. {
  348.     for my $i (0xf000..0xffff) {
  349.     $forbidden{$i} = 1;
  350.     }
  351. }
  352.  
  353. my %xkbsym_table = (
  354. # Control symbols
  355.     'BackSpace' => 'Delete',  # 0008
  356.     'Tab' => 'Tab',           # 0009
  357.     'Linefeed' => 'Linefeed', # 000a
  358.     'Return' => 'Return',     # 000d
  359.     'Escape' => 'Escape',     # 001b
  360. # Alphanumeric symbols
  361.     'space' => '0020',
  362.     'exclam' => '0021',
  363.     'quotedbl' => '0022',
  364.     'numbersign' => '0023',
  365.     'dollar' => '0024',
  366.     'percent' => '0025',
  367.     'ampersand' => '0026',
  368.     'apostrophe' => '0027',
  369.     'quoteright' => '0027',
  370.     'parenleft' => '0028',
  371.     'parenlef' => '0028', # Is this recognised by X ? (speling error)
  372.     'parenright' => '0029',
  373.     'asterisk' => '002a',
  374.     'asterix' => '002a', # Is this recognised by X ? (speling error)
  375.     'plus' => '002b',
  376.     'comma' => '002c',
  377.     'minus' => '002d',
  378.     'period' => '002e',
  379.     'slash' => '002f',
  380.     '0' => '0030',
  381.     '1' => '0031',
  382.     '2' => '0032',
  383.     '3' => '0033',
  384.     '4' => '0034',
  385.     '5' => '0035',
  386.     '6' => '0036',
  387.     '7' => '0037',
  388.     '8' => '0038',
  389.     '9' => '0039',
  390.     'colon' => '003a',
  391.     'semicolon' => '003b',
  392.     'less' => '003c',
  393.     'equal' => '003d',
  394.     'greater' => '003e',
  395.     'question' => '003f',
  396.     'at' => '0040',
  397.     'A' => '0041',
  398.     'B' => '0042',
  399.     'C' => '0043',
  400.     'D' => '0044',
  401.     'E' => '0045',
  402.     'F' => '0046',
  403.     'G' => '0047',
  404.     'H' => '0048',
  405.     'I' => '0049',
  406.     'J' => '004a',
  407.     'K' => '004b',
  408.     'L' => '004c',
  409.     'M' => '004d',
  410.     'N' => '004e',
  411.     'O' => '004f',
  412.     'P' => '0050',
  413.     'Q' => '0051',
  414.     'R' => '0052',
  415.     'S' => '0053',
  416.     'T' => '0054',
  417.     'U' => '0055',
  418.     'V' => '0056',
  419.     'W' => '0057',
  420.     'X' => '0058',
  421.     'Y' => '0059',
  422.     'Z' => '005a',
  423.     'bracketleft' => '005b',
  424.     'backslash' => '005c',
  425.     'backlash' => '005c',   # Is this recognised by X ? (speling error)
  426.     'bracketright' => '005d',
  427.     'circumflex' => '005e',
  428.     'asciicircum' => '005e',
  429.     'underscore' => '005f',
  430.     'grave' => '0060',
  431.     'quoteleft' => '0060',
  432.     'a' => '0061',
  433.     'b' => '0062',
  434.     'c' => '0063',
  435.     'd' => '0064',
  436.     'e' => '0065',
  437.     'f' => '0066',
  438.     'g' => '0067',
  439.     'h' => '0068',
  440.     'i' => '0069',
  441.     'j' => '006a',
  442.     'k' => '006b',
  443.     'l' => '006c',
  444.     'm' => '006d',
  445.     'n' => '006e',
  446.     'o' => '006f',
  447.     'p' => '0070',
  448.     'q' => '0071',
  449.     'r' => '0072',
  450.     's' => '0073',
  451.     't' => '0074',
  452.     'u' => '0075',
  453.     'v' => '0076',
  454.     'w' => '0077',
  455.     'x' => '0078',
  456.     'y' => '0079',
  457.     'z' => '007a',
  458.     'braceleft' => '007b',
  459.     'pipe' => '007c', # Is this recognised by X ?
  460.     'bar' => '007c',
  461.     'braceright' => '007d',
  462.     'asciitilde' => '007e',
  463.     'nobreakspace' => '00a0',
  464.     'exclamdown' => '00a1',
  465.     'cent' => '00a2',
  466.     'sterling' => '00a3',
  467.     'currency' => '00a4',
  468.     'yen' => '00a5',
  469.     'brokenbar' => '00a6',
  470.     'section' => '00a7',
  471.     'diaeresis' => '00a8',
  472.     'copyright' => '00a9',
  473.     'ordfeminine' => '00aa',
  474.     'guillemotleft' => '00ab',
  475.     'notsign' => '00ac',
  476.     'hyphen' => '00ad',
  477.     'registered' => '00ae',
  478.     'macron' => '00af',
  479.     'overbar' => '00af',
  480.     'degree' => '00b0',
  481.     'plusminus' => '00b1',
  482.     'twosuperior' => '00b2',
  483.     'threesuperior' => '00b3',
  484.     'acute' => '0027', # APOSTROPHE instead of ACUTE ACCENT
  485.     'mu' => '00b5',
  486.     'paragraph' => '00b6',
  487.     'periodcentered' => '00b7',
  488.     'cedilla' => '00b8',
  489.     'onesuperior' => '00b9',
  490.     'masculine' => '00ba',
  491.     'guillemotright' => '00bb',
  492.     'onequarter' => '00bc',
  493.     'onehalf' => '00bd',
  494.     'threequarters' => '00be',
  495.     'questiondown' => '00bf',
  496.     'Agrave' => '00c0',
  497.     'Aacute' => '00c1',
  498.     'Acircumflex' => '00c2',
  499.     'Atilde' => '00c3',
  500.     'Adiaeresis' => '00c4',
  501.     'Aring' => '00c5',
  502.     'AE' => '00c6',
  503.     'Ccedilla' => '00c7',
  504.     'Egrave' => '00c8',
  505.     'Eacute' => '00c9',
  506.     'Ecircumflex' => '00ca',
  507.     'Ediaeresis' => '00cb',
  508.     'Igrave' => '00cc',
  509.     'Iacute' => '00cd',
  510.     'Icircumflex' => '00ce',
  511.     'Idiaeresis' => '00cf',
  512.     'ETH' => '00d0',
  513.     'Eth' => '00d0',
  514.     'Ntilde' => '00d1',
  515.     'Ograve' => '00d2',
  516.     'Oacute' => '00d3',
  517.     'Ocircumflex' => '00d4',
  518.     'Otilde' => '00d5',
  519.     'Odiaeresis' => '00d6',
  520.     'multiply' => '00d7',
  521.     'Ooblique' => '00d8',
  522.     'Oslash' => '00d8',
  523.     'Ugrave' => '00d9',
  524.     'Uacute' => '00da',
  525.     'Ucircumflex' => '00db',
  526.     'Udiaeresis' => '00dc',
  527.     'Yacute' => '00dd',
  528.     'THORN' => '00de',
  529.     'Thorn' => '00de',
  530.     'ssharp' => '00df',
  531.     'agrave' => '00e0',
  532.     'aacute' => '00e1',
  533.     'acircumflex' => '00e2',
  534.     'atilde' => '00e3',
  535.     'adiaeresis' => '00e4',
  536.     'aring' => '00e5',
  537.     'ae' => '00e6',
  538.     'ccedilla' => '00e7',
  539.     'egrave' => '00e8',
  540.     'eacute' => '00e9',
  541.     'ecircumflex' => '00ea',
  542.     'ediaeresis' => '00eb',
  543.     'igrave' => '00ec',
  544.     'iacute' => '00ed',
  545.     'icircumflex' => '00ee',
  546.     'idiaeresis' => '00ef',
  547.     'eth' => '00f0',
  548.     'ntilde' => '00f1',
  549.     'ograve' => '00f2',
  550.     'oacute' => '00f3',
  551.     'ocircumflex' => '00f4',
  552.     'otilde' => '00f5',
  553.     'odiaeresis' => '00f6',
  554.     'division' => '00f7',
  555.     'oslash' => '00f8',
  556.     'ooblique' => '00f8',
  557.     'ugrave' => '00f9',
  558.     'uacute' => '00fa',
  559.     'ucircumflex' => '00fb',
  560.     'udiaeresis' => '00fc',
  561.     'yacute' => '00fd',
  562.     'thorn' => '00fe',
  563.     'ydiaeresis' => '00ff',
  564.     'Amacron' => '0100',
  565.     'amacron' => '0101',
  566.     'Abreve' => '0102',
  567.     'abreve' => '0103',
  568.     'Aogonek' => '0104',
  569.     'aogonek' => '0105',
  570.     'Cacute' => '0106',
  571.     'cacute' => '0107',
  572.     'Ccircumflex' => '0108',
  573.     'ccircumflex' => '0109',
  574.     'Cabovedot' => '010a',
  575.     'cabovedot' => '010b',
  576.     'Ccaron' => '010c',
  577.     'ccaron' => '010d',
  578.     'Dcaron' => '010e',
  579.     'dcaron' => '010f',
  580.     'Dstroke' => '0110',
  581.     'dstroke' => '0111',
  582.     'Emacron' => '0112',
  583.     'emacron' => '0113',
  584.     'Eabovedot' => '0116',
  585.     'eabovedot' => '0117',
  586.     'Eogonek' => '0118',
  587.     'eogonek' => '0119',
  588.     'Ecaron' => '011a',
  589.     'ecaron' => '011b',
  590.     'Gcircumflex' => '011c',
  591.     'gcircumflex' => '011d',
  592.     'Gbreve' => '011e',
  593.     'gbreve' => '011f',
  594.     'Gabovedot' => '0120',
  595.     'gabovedot' => '0121',
  596.     'Gcedilla' => '0122',
  597.     'gcedilla' => '0123',
  598.     'Hcircumflex' => '0124',
  599.     'hcircumflex' => '0125',
  600.     'Hstroke' => '0126',
  601.     'hstroke' => '0127',
  602.     'Itilde' => '0128',
  603.     'itilde' => '0129',
  604.     'Imacron' => '012a',
  605.     'imacron' => '012b',
  606.     'Ibreve' => '012c',
  607.     'ibreve' => '012d',
  608.     'Iogonek' => '012e',
  609.     'iogonek' => '012f',
  610.     'Iabovedot' => '0130',
  611.     'idotless' => '0131',
  612.     'Jcircumflex' => '0134',
  613.     'jcircumflex' => '0135',
  614.     'Kcedilla' => '0136',
  615.     'kcedilla' => '0137',
  616.     'kra' => '0138',
  617.     'Lacute' => '0139',
  618.     'lacute' => '013a',
  619.     'Lcedilla' => '013b',
  620.     'lcedilla' => '013c',
  621.     'Lcaron' => '013d',
  622.     'lcaron' => '013e',
  623.     'Lstroke' => '0141',
  624.     'lstroke' => '0142',
  625.     'Nacute' => '0143',
  626.     'nacute' => '0144',
  627.     'Ncedilla' => '0145',
  628.     'ncedilla' => '0146',
  629.     'Ncaron' => '0147',
  630.     'ncaron' => '0148',
  631.     'ENG' => '014a',
  632.     'eng' => '014b',
  633.     'Omacron' => '014c',
  634.     'omacron' => '014d',
  635.     'Odoubleacute' => '0150',
  636.     'odoubleacute' => '0151',
  637.     'OE' => '0152',
  638.     'oe' => '0153',
  639.     'Racute' => '0154',
  640.     'racute' => '0155',
  641.     'Rcedilla' => '0156',
  642.     'rcedilla' => '0157',
  643.     'Rcaron' => '0158',
  644.     'rcaron' => '0159',
  645.     'Sacute' => '015a',
  646.     'sacute' => '015b',
  647.     'Scircumflex' => '015c',
  648.     'scircumflex' => '015d',
  649.     'Scedilla' => '015e',
  650.     'scedilla' => '015f',
  651.     'Scaron' => '0160',
  652.     'scaron' => '0161',
  653.     'Tcedilla' => '0162',
  654.     'tcedilla' => '0163',
  655.     'Tcaron' => '0164',
  656.     'tcaron' => '0165',
  657.     'Tslash' => '0166',
  658.     'tslash' => '0167',
  659.     'Utilde' => '0168',
  660.     'utilde' => '0169',
  661.     'Umacron' => '016a',
  662.     'umacron' => '016b',
  663.     'Ubreve' => '016c',
  664.     'ubreve' => '016d',
  665.     'Uring' => '016e',
  666.     'uring' => '016f',
  667.     'Udoubleacute' => '0170',
  668.     'udoubleacute' => '0171',
  669.     'Uogonek' => '0172',
  670.     'uogonek' => '0173',
  671.     'Wcircumflex' => '0174',
  672.     'wcircumflex' => '0175',
  673.     'Ycircumflex' => '0176',
  674.     'ycircumflex' => '0177',
  675.     'Ydiaeresis' => '0178',
  676.     'Zacute' => '0179',
  677.     'zacute' => '017a',
  678.     'Zabovedot' => '017b',
  679.     'zabovedot' => '017c',
  680.     'Zcaron' => '017d',
  681.     'zcaron' => '017e',
  682.     'SCHWA' => '018f',
  683.     'Schwa' => '018f', # Is this recognised by X ?
  684.     'function' => '0192',
  685.     'Obarred' => '019f',
  686.     'Ohorn' => '01a0', # Is this recognised by X ?
  687.     'ohorn' => '01a1', # Is this recognised by X ?
  688.     'Uhorn' => '01af',
  689.     'uhorn' => '01b0',
  690.     'Zstroke' => '01b5',
  691.     'zstroke' => '01b6',
  692.     'Ocaron' => '01d1',
  693.     'ocaron' => '01d2',
  694.     'Gcaron' => '01e6', # Is this recognised by X ?
  695.     'gcaron' => '01e7', # Is this recognised by X ?
  696.     'schwa' => '0259', # Is this recognised by X ?
  697.     'obarred' => '0275',
  698.     'caron' => '02c7',
  699.     'breve' => '02d8',
  700.     'abovedot' => '02d9',
  701.     'ogonek' => '02db',
  702.     'doubleacute' => '02dd',
  703.     'Greek_accentdieresis' => '0385',
  704.     'Greek_ALPHAaccent' => '0386',
  705.     'Greek_EPSILONaccent' => '0388',
  706.     'Greek_ETAaccent' => '0389',
  707.     'Greek_IOTAaccent' => '038a',
  708.     'Greek_OMICRONaccent' => '038c',
  709.     'Greek_UPSILONaccent' => '038e',
  710.     'Greek_OMEGAaccent' => '038f',
  711.     'Greek_iotaaccentdieresis' => '0390',
  712.     'Greek_ALPHA' => '0391',
  713.     'Greek_BETA' => '0392',
  714.     'Greek_GAMMA' => '0393',
  715.     'Greek_DELTA' => '0394',
  716.     'Greek_EPSILON' => '0395',
  717.     'Greek_ZETA' => '0396',
  718.     'Greek_ETA' => '0397',
  719.     'Greek_THETA' => '0398',
  720.     'Greek_IOTA' => '0399',
  721.     'Greek_KAPPA' => '039a',
  722.     'Greek_LAMBDA' => '039b',
  723.     'Greek_LAMDA' => '039b',   # Is this recognised by X ? (speling error)
  724.     'Greek_MU' => '039c',
  725.     'Greek_NU' => '039d',
  726.     'Greek_XI' => '039e',
  727.     'Greek_OMICRON' => '039f',
  728.     'Greek_PI' => '03a0',
  729.     'Greek_RHO' => '03a1',
  730.     'Greek_SIGMA' => '03a3',
  731.     'Greek_TAU' => '03a4',
  732.     'Greek_UPSILON' => '03a5',
  733.     'Greek_PHI' => '03a6',
  734.     'Greek_CHI' => '03a7',
  735.     'Greek_PSI' => '03a8',
  736.     'Greek_OMEGA' => '03a9',
  737.     'Greek_IOTAdiaeresis' => '03aa',
  738.     'Greek_UPSILONdieresis' => '03ab',
  739.     'Greek_alphaaccent' => '03ac',
  740.     'Greek_epsilonaccent' => '03ad',
  741.     'Greek_etaaccent' => '03ae',
  742.     'Greek_iotaaccent' => '03af',
  743.     'Greek_upsilonaccentdieresis' => '03b0',
  744.     'Greek_alpha' => '03b1',
  745.     'Greek_beta' => '03b2',
  746.     'Greek_gamma' => '03b3',
  747.     'Greek_delta' => '03b4',
  748.     'Greek_epsilon' => '03b5',
  749.     'Greek_zeta' => '03b6',
  750.     'Greek_eta' => '03b7',
  751.     'Greek_theta' => '03b8',
  752.     'Greek_iota' => '03b9',
  753.     'Greek_kappa' => '03ba',
  754.     'Greek_lambda' => '03bb',
  755.     'Greek_lamda' => '03bb', # Is this recognised by X ? (speling error)
  756.     'Greek_mu' => '03bc',
  757.     'Greek_nu' => '03bd',
  758.     'Greek_xi' => '03be',
  759.     'Greek_omicron' => '03bf',
  760.     'Greek_pi' => '03c0',
  761.     'Greek_rho' => '03c1',
  762.     'Greek_finalsmallsigma' => '03c2',
  763.     'Greek_sigma' => '03c3',
  764.     'Greek_tau' => '03c4',
  765.     'Greek_upsilon' => '03c5',
  766.     'Greek_phi' => '03c6',
  767.     'Greek_chi' => '03c7',
  768.     'Greek_psi' => '03c8',
  769.     'Greek_omega' => '03c9',
  770.     'Greek_iotadieresis' => '03ca',
  771.     'Greek_upsilondieresis' => '03cb',
  772.     'Greek_omicronaccent' => '03cc',
  773.     'Greek_upsilonaccent' => '03cd',
  774.     'Greek_omegaaccent' => '03ce',
  775.     'Cyrillic_IO' => '0401',
  776.     'Serbian_DJE' => '0402',
  777.     'Macedonia_GJE' => '0403',
  778.     'Ukrainian_IE' => '0404',
  779.     'Macedonia_DSE' => '0405',
  780.     'Ukrainian_I' => '0406',
  781.     'Ukrainian_YI' => '0407',
  782.     'Cyrillic_JE' => '0408',
  783.     'Cyrillic_LJE' => '0409',
  784.     'Cyrillic_NJE' => '040a',
  785.     'Serbian_TSHE' => '040b',
  786.     'Macedonia_KJE' => '040c',
  787.     'Byelorussian_SHORTU' => '040e',
  788.     'Cyrillic_DZHE' => '040f',
  789.     'Cyrillic_A' => '0410',
  790.     'Cyrillic_BE' => '0411',
  791.     'Cyrillic_VE' => '0412',
  792.     'Cyrillic_GHE' => '0413',
  793.     'Cyrillic_DE' => '0414',
  794.     'Cyrillic_IE' => '0415',
  795.     'Cyrillic_ZHE' => '0416',
  796.     'Cyrillic_ZE' => '0417',
  797.     'Cyrillic_I' => '0418',
  798.     'Cyrillic_SHORTI' => '0419',
  799.     'Cyrillic_KA' => '041a',
  800.     'Cyrillic_EL' => '041b',
  801.     'Cyrillic_EM' => '041c',
  802.     'Cyrillic_EN' => '041d',
  803.     'Cyrillic_O' => '041e',
  804.     'Cyrillic_PE' => '041f',
  805.     'Cyrillic_ER' => '0420',
  806.     'Cyrillic_ES' => '0421',
  807.     'Cyrillic_TE' => '0422',
  808.     'Cyrillic_U' => '0423',
  809.     'Cyrillic_EF' => '0424',
  810.     'Cyrillic_HA' => '0425',
  811.     'Cyrillic_TSE' => '0426',
  812.     'Cyrillic_CHE' => '0427',
  813.     'Cyrillic_SHA' => '0428',
  814.     'Cyrillic_SHCHA' => '0429',
  815.     'Cyrillic_HARDSIGN' => '042a',
  816.     'Cyrillic_YERU' => '042b',
  817.     'Cyrillic_SOFTSIGN' => '042c',
  818.     'Cyrillic_E' => '042d',
  819.     'Cyrillic_YU' => '042e',
  820.     'Cyrillic_YA' => '042f',
  821.     'Cyrillic_a' => '0430',
  822.     'Cyrillic_be' => '0431',
  823.     'Cyrillic_ve' => '0432',
  824.     'Cyrillic_ghe' => '0433',
  825.     'Cyrillic_de' => '0434',
  826.     'Cyrillic_ie' => '0435',
  827.     'Cyrillic_zhe' => '0436',
  828.     'Cyrillic_ze' => '0437',
  829.     'Cyrillic_i' => '0438',
  830.     'Cyrillic_shorti' => '0439',
  831.     'Cyrillic_ka' => '043a',
  832.     'Cyrillic_el' => '043b',
  833.     'Cyrillic_em' => '043c',
  834.     'Cyrillic_en' => '043d',
  835.     'Cyrillic_o' => '043e',
  836.     'Cyrillic_pe' => '043f',
  837.     'Cyrillic_er' => '0440',
  838.     'Cyrillic_es' => '0441',
  839.     'Cyrillic_te' => '0442',
  840.     'Cyrillic_u' => '0443',
  841.     'Cyrillic_ef' => '0444',
  842.     'Cyrillic_ha' => '0445',
  843.     'Cyrillic_tse' => '0446',
  844.     'Cyrillic_che' => '0447',
  845.     'Cyrillic_sha' => '0448',
  846.     'Cyrillic_shcha' => '0449',
  847.     'Cyrillic_hardsign' => '044a',
  848.     'Cyrillic_yeru' => '044b',
  849.     'Cyrillic_softsign' => '044c',
  850.     'Cyrillic_e' => '044d',
  851.     'Cyrillic_yu' => '044e',
  852.     'Cyrillic_ya' => '044f',
  853.     'Cyrillic_io' => '0451',
  854.     'Serbian_dje' => '0452',
  855.     'Macedonia_gje' => '0453',
  856.     'Ukrainian_ie' => '0454',
  857.     'Macedonia_dse' => '0455',
  858.     'Ukrainian_i' => '0456',
  859.     'Ukrainian_yi' => '0457',
  860.     'Cyrillic_je' => '0458',
  861.     'Cyrillic_lje' => '0459',
  862.     'Cyrillic_nje' => '045a',
  863.     'Serbian_tshe' => '045b',
  864.     'Macedonia_kje' => '045c',
  865.     'Byelorussian_shortu' => '045e',
  866.     'Cyrillic_dzhe' => '045f',
  867.     'Ukrainian_GHE_WITH_UPTURN' => '0490', # Is this recognised by X ?
  868.     'Ukrainian_ghe_with_upturn' => '0491', # Is this recognised by X ?
  869.     'Cyrillic_GHE_bar' => '0492', # Is this recognised by X ?
  870.     'Cyrillic_ghe_bar' => '0493', # Is this recognised by X ?
  871.     'Cyrillic_ZHE_descender' => '0496',
  872.     'Cyrillic_zhe_descender' => '0497',
  873.     'Cyrillic_KA_descender' => '049a', # Is this recognised by X ?
  874.     'Cyrillic_ka_descender' => '049b', # Is this recognised by X ?
  875.     'Cyrillic_KA_vertstroke' => '049c', # Is this recognised by X ?
  876.     'Cyrillic_ka_vertstroke' => '049d', # Is this recognised by X ?
  877.     'Cyrillic_EN_descender' => '04a2', # Is this recognised by X ?
  878.     'Cyrillic_en_descender' => '04a3', # Is this recognised by X ?
  879.     'Cyrillic_U_straight' => '04ae', # Is this recognised by X ?
  880.     'Cyrillic_u_straight' => '04af', # Is this recognised by X ?
  881.     'Cyrillic_U_straight_bar' => '04b0', # Is this recognised by X ?
  882.     'Cyrillic_u_straight_bar' => '04b1', # Is this recognised by X ?
  883.     'Cyrillic_HA_descender' => '04b2', # Is this recognised by X ?
  884.     'Cyrillic_ha_descender' => '04b3', # Is this recognised by X ?
  885.     'Cyrillic_CHE_descender' => '04b6',
  886.     'Cyrillic_che_descender' => '04b7',
  887.     'Cyrillic_CHE_vertstroke' => '04b8', # Is this recognised by X ?
  888.     'Cyrillic_che_vertstroke' => '04b9', # Is this recognised by X ?
  889.     'Cyrillic_SHHA' => '04ba', # Is this recognised by X ?
  890.     'Cyrillic_shha' => '04bb', # Is this recognised by X ?
  891.     'Cyrillic_SCHWA' => '04d8', # Is this recognised by X ?
  892.     'Cyrillic_schwa' => '04d9', # Is this recognised by X ?
  893.     'Cyrillic_I_macron' => '04e2',
  894.     'Cyrillic_i_macron' => '04e3',
  895.     'Cyrillic_O_bar' => '04e8', # Is this recognised by X ?
  896.     'Cyrillic_o_bar' => '04e9', # Is this recognised by X ?
  897.     'Cyrillic_U_macron' => '04ee',
  898.     'Cyrillic_u_macron' => '04ef',
  899.     'Armenian_AYB' => '0531',
  900.     'Armenian_BEN' => '0532',
  901.     'Armenian_GIM' => '0533',
  902.     'Armenian_DA' => '0534',
  903.     'Armenian_YECH' => '0535',
  904.     'Armenian_ZA' => '0536',
  905.     'Armenian_E' => '0537',
  906.     'Armenian_AT' => '0538',
  907.     'Armenian_TO' => '0539',
  908.     'Armenian_ZHE' => '053a',
  909.     'Armenian_INI' => '053b',
  910.     'Armenian_LYUN' => '053c',
  911.     'Armenian_KHE' => '053d',
  912.     'Armenian_TSA' => '053e',
  913.     'Armenian_KEN' => '053f',
  914.     'Armenian_HO' => '0540',
  915.     'Armenian_DZA' => '0541',
  916.     'Armenian_GHAT' => '0542',
  917.     'Armenian_TCHE' => '0543',
  918.     'Armenian_MEN' => '0544',
  919.     'Armenian_HI' => '0545',
  920.     'Armenian_NU' => '0546',
  921.     'Armenian_SHA' => '0547',
  922.     'Armenian_VO' => '0548',
  923.     'Armenian_CHA' => '0549',
  924.     'Armenian_PE' => '054a',
  925.     'Armenian_JE' => '054b',
  926.     'Armenian_RA' => '054c',
  927.     'Armenian_SE' => '054d',
  928.     'Armenian_VEV' => '054e',
  929.     'Armenian_TYUN' => '054f',
  930.     'Armenian_RE' => '0550',
  931.     'Armenian_TSO' => '0551',
  932.     'Armenian_VYUN' => '0552',
  933.     'Armenian_PYUR' => '0553',
  934.     'Armenian_KE' => '0554',
  935.     'Armenian_O' => '0555',
  936.     'Armenian_FE' => '0556',
  937.     'Armenian_apostrophe' => '055a',
  938.     'Armenian_accent' => '055b',
  939.     'Armenian_shesht' => '055b',
  940.     'Armenian_amanak' => '055c',
  941.     'Armenian_exclam' => '055c',
  942.     'Armenian_but' => '055d',
  943.     'Armenian_separation_mark' => '055d',
  944.     'Armenian_paruyk' => '055e',
  945.     'Armenian_question' => '055e',
  946.     'Armenian_ayb' => '0561',
  947.     'Armenian_ben' => '0562',
  948.     'Armenian_gim' => '0563',
  949.     'Armenian_da' => '0564',
  950.     'Armenian_yech' => '0565',
  951.     'Armenian_za' => '0566',
  952.     'Armenian_e' => '0567',
  953.     'Armenian_at' => '0568',
  954.     'Armenian_to' => '0569',
  955.     'Armenian_zhe' => '056a',
  956.     'Armenian_ini' => '056b',
  957.     'Armenian_lyun' => '056c',
  958.     'Armenian_khe' => '056d',
  959.     'Armenian_tsa' => '056e',
  960.     'Armenian_ken' => '056f',
  961.     'Armenian_ho' => '0570',
  962.     'Armenian_dza' => '0571',
  963.     'Armenian_ghat' => '0572',
  964.     'Armenian_tche' => '0573',
  965.     'Armenian_men' => '0574',
  966.     'Armenian_hi' => '0575',
  967.     'Armenian_nu' => '0576',
  968.     'Armenian_sha' => '0577',
  969.     'Armenian_vo' => '0578',
  970.     'Armenian_cha' => '0579',
  971.     'Armenian_pe' => '057a',
  972.     'Armenian_je' => '057b',
  973.     'Armenian_ra' => '057c',
  974.     'Armenian_se' => '057d',
  975.     'Armenian_vev' => '057e',
  976.     'Armenian_tyun' => '057f',
  977.     'Armenian_re' => '0580',
  978.     'Armenian_tso' => '0581',
  979.     'Armenian_vyun' => '0582',
  980.     'Armenian_pyur' => '0583',
  981.     'Armenian_ke' => '0584',
  982.     'Armenian_o' => '0585',
  983.     'Armenian_fe' => '0586',
  984.     'Armenian_ligature_ew' => '0587',
  985.     'Armenian_full_stop' => '0589',
  986.     'Armenian_verjaket' => '0589',
  987.     'Armenian_hyphen' => '058a',
  988.     'Armenian_yentamna' => '058a',
  989.     'hebrew_aleph' => '05d0',
  990.     'hebrew_bet' => '05d1',
  991.     'hebrew_gimel' => '05d2',
  992.     'hebrew_dalet' => '05d3',
  993.     'hebrew_he' => '05d4',
  994.     'hebrew_waw' => '05d5',
  995.     'hebrew_zain' => '05d6',
  996.     'hebrew_chet' => '05d7',
  997.     'hebrew_tet' => '05d8',
  998.     'hebrew_yod' => '05d9',
  999.     'hebrew_finalkaph' => '05da',
  1000.     'hebrew_kaph' => '05db',
  1001.     'hebrew_lamed' => '05dc',
  1002.     'hebrew_finalmem' => '05dd',
  1003.     'hebrew_mem' => '05de',
  1004.     'hebrew_finalnun' => '05df',
  1005.     'hebrew_nun' => '05e0',
  1006.     'hebrew_samech' => '05e1',
  1007.     'hebrew_ayin' => '05e2',
  1008.     'hebrew_finalpe' => '05e3',
  1009.     'hebrew_pe' => '05e4',
  1010.     'hebrew_finalzade' => '05e5',
  1011.     'hebrew_zade' => '05e6',
  1012.     'hebrew_qoph' => '05e7',
  1013.     'hebrew_resh' => '05e8',
  1014.     'hebrew_shin' => '05e9',
  1015.     'hebrew_taw' => '05ea',
  1016.     'Arabic_comma' => '060c',
  1017.     'Arabic_semicolon' => '061b',
  1018.     'Arabic_question_mark' => '061f',
  1019.     'Arabic_hamza' => '0621',
  1020.     'Arabic_maddaonalef' => '0622',
  1021.     'Arabic_hamzaonalef' => '0623',
  1022.     'Arabic_hamzaonwaw' => '0624',
  1023.     'Arabic_hamzaunderalef' => '0625',
  1024.     'Arabic_hamzaonyeh' => '0626',
  1025.     'Arabic_alef' => '0627',
  1026.     'Arabic_beh' => '0628',
  1027.     'Arabic_tehmarbuta' => '0629',
  1028.     'Arabic_teh' => '062a',
  1029.     'Arabic_theh' => '062b',
  1030.     'Arabic_jeem' => '062c',
  1031.     'Arabic_hah' => '062d',
  1032.     'Arabic_khah' => '062e',
  1033.     'Arabic_dal' => '062f',
  1034.     'Arabic_thal' => '0630',
  1035.     'Arabic_ra' => '0631',
  1036.     'Arabic_zain' => '0632',
  1037.     'Arabic_seen' => '0633',
  1038.     'Arabic_sheen' => '0634',
  1039.     'Arabic_sad' => '0635',
  1040.     'Arabic_dad' => '0636',
  1041.     'Arabic_tah' => '0637',
  1042.     'Arabic_zah' => '0638',
  1043.     'Arabic_ain' => '0639',
  1044.     'Arabic_ghain' => '063a',
  1045.     'Arabic_tatweel' => '0640',
  1046.     'Arabic_feh' => '0641',
  1047.     'Arabic_qaf' => '0642',
  1048.     'Arabic_kaf' => '0643',
  1049.     'Arabic_lam' => '0644',
  1050.     'Arabic_meem' => '0645',
  1051.     'Arabic_noon' => '0646',
  1052.     'Arabic_ha' => '0647',
  1053.     'Arabic_heh' => '0647', # Is this recognised by X ?
  1054.     'Arabic_waw' => '0648',
  1055.     'Arabic_alefmaksura' => '0649',
  1056.     'Arabic_yeh' => '064a',
  1057.     'Arabic_fathatan' => '064b',
  1058.     'Arabic_dammatan' => '064c',
  1059.     'Arabic_kasratan' => '064d',
  1060.     'Arabic_fatha' => '064e',
  1061.     'Arabic_damma' => '064f',
  1062.     'Arabic_kasra' => '0650',
  1063.     'Arabic_shadda' => '0651',
  1064.     'Arabic_sukun' => '0652',
  1065.     'Arabic_madda_above' => '0653', # Is this recognised by X ?
  1066.     'Arabic_hamza_above' => '0654', # Is this recognised by X ?
  1067.     'Arabic_hamza_below' => '0655', # Is this recognised by X ?
  1068.     'Arabic_0' => '0660',
  1069.     'Arabic_1' => '0661',
  1070.     'Arabic_2' => '0662',
  1071.     'Arabic_3' => '0663',
  1072.     'Arabic_4' => '0664',
  1073.     'Arabic_5' => '0665',
  1074.     'Arabic_6' => '0666',
  1075.     'Arabic_7' => '0667',
  1076.     'Arabic_8' => '0668',
  1077.     'Arabic_9' => '0669',
  1078.     'Arabic_percent' => '066a',
  1079.     'Arabic_superscript_alef' => '0670', # Is this recognised by X ?
  1080.     'Arabic_tteh' => '0679',
  1081.     'Arabic_peh' => '067e',
  1082.     'Arabic_tcheh' => '0686',
  1083.     'Arabic_ddal' => '0688',
  1084.     'Arabic_rreh' => '0691',
  1085.     'Arabic_jeh' => '0698',
  1086.     'Arabic_veh' => '06a4',
  1087.     'Arabic_keheh' => '06a9',
  1088.     'Arabic_gaf' => '06af',
  1089.     'Arabic_noon_ghunna' => '06ba',
  1090.     'Arabic_heh_doachashmee' => '06be',
  1091.     'Arabic_heh_goal' => '06c1',
  1092.     'Arabic_farsi_yeh' => '06cc',
  1093.     'Farsi_yeh' => '06cc',
  1094.     'Arabic_yeh_baree' => '06d2',
  1095.     'Arabic_fullstop' => '06d4',
  1096.     'Farsi_0' => '06f0',
  1097.     'Farsi_1' => '06f1',
  1098.     'Farsi_2' => '06f2',
  1099.     'Farsi_3' => '06f3',
  1100.     'Farsi_4' => '06f4',
  1101.     'Farsi_5' => '06f5',
  1102.     'Farsi_6' => '06f6',
  1103.     'Farsi_7' => '06f7',
  1104.     'Farsi_8' => '06f8',
  1105.     'Farsi_9' => '06f9',
  1106.     'Thai_kokai' => '0e01',
  1107.     'Thai_khokhai' => '0e02',
  1108.     'Thai_khokhuat' => '0e03',
  1109.     'Thai_khokhwai' => '0e04',
  1110.     'Thai_khokhon' => '0e05',
  1111.     'Thai_khorakhang' => '0e06',
  1112.     'Thai_ngongu' => '0e07',
  1113.     'Thai_chochan' => '0e08',
  1114.     'Thai_choching' => '0e09',
  1115.     'Thai_chochang' => '0e0a',
  1116.     'Thai_soso' => '0e0b',
  1117.     'Thai_chochoe' => '0e0c',
  1118.     'Thai_yoying' => '0e0d',
  1119.     'Thai_dochada' => '0e0e',
  1120.     'Thai_topatak' => '0e0f',
  1121.     'Thai_thothan' => '0e10',
  1122.     'Thai_thonangmontho' => '0e11',
  1123.     'Thai_thophuthao' => '0e12',
  1124.     'Thai_nonen' => '0e13',
  1125.     'Thai_dodek' => '0e14',
  1126.     'Thai_totao' => '0e15',
  1127.     'Thai_thothung' => '0e16',
  1128.     'Thai_thothahan' => '0e17',
  1129.     'Thai_thothong' => '0e18',
  1130.     'Thai_nonu' => '0e19',
  1131.     'Thai_bobaimai' => '0e1a',
  1132.     'Thai_popla' => '0e1b',
  1133.     'Thai_phophung' => '0e1c',
  1134.     'Thai_fofa' => '0e1d',
  1135.     'Thai_phophan' => '0e1e',
  1136.     'Thai_fofan' => '0e1f',
  1137.     'Thai_phosamphao' => '0e20',
  1138.     'Thai_moma' => '0e21',
  1139.     'Thai_yoyak' => '0e22',
  1140.     'Thai_rorua' => '0e23',
  1141.     'Thai_ru' => '0e24',
  1142.     'Thai_loling' => '0e25',
  1143.     'Thai_lu' => '0e26',
  1144.     'Thai_wowaen' => '0e27',
  1145.     'Thai_sosala' => '0e28',
  1146.     'Thai_sorusi' => '0e29',
  1147.     'Thai_sosua' => '0e2a',
  1148.     'Thai_hohip' => '0e2b',
  1149.     'Thai_lochula' => '0e2c',
  1150.     'Thai_oang' => '0e2d',
  1151.     'Thai_honokhuk' => '0e2e',
  1152.     'Thai_paiyannoi' => '0e2f',
  1153.     'Thai_saraa' => '0e30',
  1154.     'Thai_maihanakat' => '0e31',
  1155.     'Thai_saraaa' => '0e32',
  1156.     'Thai_saraam' => '0e33',
  1157.     'Thai_sarai' => '0e34',
  1158.     'Thai_saraii' => '0e35',
  1159.     'Thai_saraue' => '0e36',
  1160.     'Thai_sarauee' => '0e37',
  1161.     'Thai_sarau' => '0e38',
  1162.     'Thai_sarauu' => '0e39',
  1163.     'Thai_phinthu' => '0e3a',
  1164.     'Thai_baht' => '0e3f',
  1165.     'Thai_sarae' => '0e40',
  1166.     'Thai_saraae' => '0e41',
  1167.     'Thai_sarao' => '0e42',
  1168.     'Thai_saraaimaimuan' => '0e43',
  1169.     'Thai_saraaimaimalai' => '0e44',
  1170.     'Thai_lakkhangyao' => '0e45',
  1171.     'Thai_maiyamok' => '0e46',
  1172.     'Thai_maitaikhu' => '0e47',
  1173.     'Thai_maiek' => '0e48',
  1174.     'Thai_maitho' => '0e49',
  1175.     'Thai_maitri' => '0e4a',
  1176.     'Thai_maichattawa' => '0e4b',
  1177.     'Thai_thanthakhat' => '0e4c',
  1178.     'Thai_nikhahit' => '0e4d',
  1179.     'Thai_leksun' => '0e50',
  1180.     'Thai_leknung' => '0e51',
  1181.     'Thai_leksong' => '0e52',
  1182.     'Thai_leksam' => '0e53',
  1183.     'Thai_leksi' => '0e54',
  1184.     'Thai_lekha' => '0e55',
  1185.     'Thai_lekhok' => '0e56',
  1186.     'Thai_lekchet' => '0e57',
  1187.     'Thai_lekpaet' => '0e58',
  1188.     'Thai_lekkao' => '0e59',
  1189.     'Georgian_an' => '10d0',
  1190.     'Georgian_ban' => '10d1',
  1191.     'Georgian_gan' => '10d2',
  1192.     'Georgian_don' => '10d3',
  1193.     'Georgian_en' => '10d4',
  1194.     'Georgian_vin' => '10d5',
  1195.     'Georgian_zen' => '10d6',
  1196.     'Georgian_tan' => '10d7',
  1197.     'Georgian_in' => '10d8',
  1198.     'Georgian_kan' => '10d9',
  1199.     'Georgian_las' => '10da',
  1200.     'Georgian_man' => '10db',
  1201.     'Georgian_nar' => '10dc',
  1202.     'Georgian_on' => '10dd',
  1203.     'Georgian_par' => '10de',
  1204.     'Georgian_zhar' => '10df',
  1205.     'Georgian_rae' => '10e0',
  1206.     'Georgian_san' => '10e1',
  1207.     'Georgian_tar' => '10e2',
  1208.     'Georgian_un' => '10e3',
  1209.     'Georgian_phar' => '10e4',
  1210.     'Georgian_khar' => '10e5',
  1211.     'Georgian_ghan' => '10e6',
  1212.     'Georgian_qar' => '10e7',
  1213.     'Georgian_shin' => '10e8',
  1214.     'Georgian_chin' => '10e9',
  1215.     'Georgian_can' => '10ea',
  1216.     'Georgian_jil' => '10eb',
  1217.     'Georgian_cil' => '10ec',
  1218.     'Georgian_char' => '10ed',
  1219.     'Georgian_xan' => '10ee',
  1220.     'Georgian_jhan' => '10ef',
  1221.     'Georgian_hae' => '10f0',
  1222.     'Georgian_he' => '10f1',
  1223.     'Georgian_hie' => '10f2',
  1224.     'Georgian_we' => '10f3',
  1225.     'Georgian_har' => '10f4',
  1226.     'Georgian_hoe' => '10f5',
  1227.     'Georgian_fi' => '10f6',
  1228.     'Hangul_J_Kiyeog' => '11a8',
  1229.     'Hangul_J_SsangKiyeog' => '11a9',
  1230.     'Hangul_J_KiyeogSios' => '11aa',
  1231.     'Hangul_J_Nieun' => '11ab',
  1232.     'Hangul_J_NieunJieuj' => '11ac',
  1233.     'Hangul_J_NieunHieuh' => '11ad',
  1234.     'Hangul_J_Dikeud' => '11ae',
  1235.     'Hangul_J_Rieul' => '11af',
  1236.     'Hangul_J_RieulKiyeog' => '11b0',
  1237.     'Hangul_J_RieulMieum' => '11b1',
  1238.     'Hangul_J_RieulPieub' => '11b2',
  1239.     'Hangul_J_RieulSios' => '11b3',
  1240.     'Hangul_J_RieulTieut' => '11b4',
  1241.     'Hangul_J_RieulPhieuf' => '11b5',
  1242.     'Hangul_J_RieulHieuh' => '11b6',
  1243.     'Hangul_J_Mieum' => '11b7',
  1244.     'Hangul_J_Pieub' => '11b8',
  1245.     'Hangul_J_PieubSios' => '11b9',
  1246.     'Hangul_J_Sios' => '11ba',
  1247.     'Hangul_J_SsangSios' => '11bb',
  1248.     'Hangul_J_Ieung' => '11bc',
  1249.     'Hangul_J_Jieuj' => '11bd',
  1250.     'Hangul_J_Cieuc' => '11be',
  1251.     'Hangul_J_Khieuq' => '11bf',
  1252.     'Hangul_J_Tieut' => '11c0',
  1253.     'Hangul_J_Phieuf' => '11c1',
  1254.     'Hangul_J_Hieuh' => '11c2',
  1255.     'Hangul_J_PanSios' => '11eb',
  1256.     'Hangul_J_KkogjiDalrinIeung' => '11f0',
  1257.     'Hangul_J_YeorinHieuh' => '11f9',
  1258.     'Babovedot' => '1e02', # Is this recognised by X ?
  1259.     'babovedot' => '1e03', # Is this recognised by X ?
  1260.     'Dabovedot' => '1e0a', # Is this recognised by X ?
  1261.     'dabovedot' => '1e0b', # Is this recognised by X ?
  1262.     'Fabovedot' => '1e1e', # Is this recognised by X ?
  1263.     'fabovedot' => '1e1f', # Is this recognised by X ?
  1264.     'Lbelowdot' => '1e36',
  1265.     'lbelowdot' => '1e37',
  1266.     'Mabovedot' => '1e40', # Is this recognised by X ?
  1267.     'mabovedot' => '1e41', # Is this recognised by X ?
  1268.     'Pabovedot' => '1e56', # Is this recognised by X ?
  1269.     'pabovedot' => '1e57', # Is this recognised by X ?
  1270.     'Sabovedot' => '1e60', # Is this recognised by X ?
  1271.     'sabovedot' => '1e61', # Is this recognised by X ?
  1272.     'Tabovedot' => '1e6a', # Is this recognised by X ?
  1273.     'tabovedot' => '1e6b', # Is this recognised by X ?
  1274.     'Wgrave' => '1e80',
  1275.     'wgrave' => '1e81',
  1276.     'Wacute' => '1e82',
  1277.     'wacute' => '1e83',
  1278.     'Wdiaeresis' => '1e84',
  1279.     'wdiaeresis' => '1e85',
  1280.     'Xabovedot' => '1e8a',
  1281.     'xabovedot' => '1e8b',
  1282.     'Abelowdot' => '1ea0',
  1283.     'abelowdot' => '1ea1',
  1284.     'Ahook' => '1ea2',
  1285.     'ahook' => '1ea3',
  1286.     'Acircumflexacute' => '1ea4',
  1287.     'acircumflexacute' => '1ea5',
  1288.     'Acircumflexgrave' => '1ea6',
  1289.     'acircumflexgrave' => '1ea7',
  1290.     'Acircumflexhook' => '1ea8',
  1291.     'acircumflexhook' => '1ea9',
  1292.     'Acircumflextilde' => '1eaa',
  1293.     'acircumflextilde' => '1eab',
  1294.     'Acircumflexbelowdot' => '1eac',
  1295.     'acircumflexbelowdot' => '1ead',
  1296.     'Abreveacute' => '1eae',
  1297.     'abreveacute' => '1eaf',
  1298.     'Abrevegrave' => '1eb0',
  1299.     'abrevegrave' => '1eb1',
  1300.     'Abrevehook' => '1eb2',
  1301.     'abrevehook' => '1eb3',
  1302.     'Abrevetilde' => '1eb4',
  1303.     'abrevetilde' => '1eb5',
  1304.     'Abrevebelowdot' => '1eb6',
  1305.     'abrevebelowdot' => '1eb7',
  1306.     'Ebelowdot' => '1eb8',
  1307.     'ebelowdot' => '1eb9',
  1308.     'Ehook' => '1eba',
  1309.     'ehook' => '1ebb',
  1310.     'Etilde' => '1ebc',
  1311.     'etilde' => '1ebd',
  1312.     'Ecircumflexacute' => '1ebe',
  1313.     'ecircumflexacute' => '1ebf',
  1314.     'Ecircumflexgrave' => '1ec0',
  1315.     'ecircumflexgrave' => '1ec1',
  1316.     'Ecircumflexhook' => '1ec2',
  1317.     'ecircumflexhook' => '1ec3',
  1318.     'Ecircumflextilde' => '1ec4',
  1319.     'ecircumflextilde' => '1ec5',
  1320.     'Ecircumflexbelowdot' => '1ec6',
  1321.     'ecircumflexbelowdot' => '1ec7',
  1322.     'Ihook' => '1ec8',
  1323.     'ihook' => '1ec9',
  1324.     'Ibelowdot' => '1eca',
  1325.     'ibelowdot' => '1ecb',
  1326.     'Obelowdot' => '1ecc',
  1327.     'obelowdot' => '1ecd',
  1328.     'Ohook' => '1ece',
  1329.     'ohook' => '1ecf',
  1330.     'Ocircumflexacute' => '1ed0',
  1331.     'ocircumflexacute' => '1ed1',
  1332.     'Ocircumflexgrave' => '1ed2',
  1333.     'ocircumflexgrave' => '1ed3',
  1334.     'Ocircumflexhook' => '1ed4',
  1335.     'ocircumflexhook' => '1ed5',
  1336.     'Ocircumflextilde' => '1ed6',
  1337.     'ocircumflextilde' => '1ed7',
  1338.     'Ocircumflexbelowdot' => '1ed8',
  1339.     'ocircumflexbelowdot' => '1ed9',
  1340.     'Ohornacute' => '1eda',
  1341.     'ohornacute' => '1edb',
  1342.     'Ohorngrave' => '1edc',
  1343.     'ohorngrave' => '1edd',
  1344.     'Ohornhook' => '1ede',
  1345.     'ohornhook' => '1edf',
  1346.     'Ohorntilde' => '1ee0',
  1347.     'ohorntilde' => '1ee1',
  1348.     'Ohornbelowdot' => '1ee2',
  1349.     'ohornbelowdot' => '1ee3',
  1350.     'Ubelowdot' => '1ee4',
  1351.     'ubelowdot' => '1ee5',
  1352.     'Uhook' => '1ee6',
  1353.     'uhook' => '1ee7',
  1354.     'Uhornacute' => '1ee8',
  1355.     'uhornacute' => '1ee9',
  1356.     'Uhorngrave' => '1eea',
  1357.     'uhorngrave' => '1eeb',
  1358.     'Uhornhook' => '1eec',
  1359.     'uhornhook' => '1eed',
  1360.     'Uhorntilde' => '1eee',
  1361.     'uhorntilde' => '1eef',
  1362.     'Uhornbelowdot' => '1ef0',
  1363.     'uhornbelowdot' => '1ef1',
  1364.     'Ygrave' => '1ef2',
  1365.     'ygrave' => '1ef3',
  1366.     'Ybelowdot' => '1ef4',
  1367.     'ybelowdot' => '1ef5',
  1368.     'Yhook' => '1ef6',
  1369.     'yhook' => '1ef7',
  1370.     'Ytilde' => '1ef8',
  1371.     'ytilde' => '1ef9',
  1372.     'enspace' => '2002',
  1373.     'emspace' => '2003',
  1374.     'em3space' => '2004',
  1375.     'em4space' => '2005',
  1376.     'digitspace' => '2007',
  1377.     'punctspace' => '2008',
  1378.     'thinspace' => '2009',
  1379.     'hairspace' => '200a',
  1380.     'figdash' => '2012',
  1381.     'endash' => '2013',
  1382.     'emdash' => '2014',
  1383.     'Greek_horizbar' => '2015',
  1384.     'hebrew_doublelowline' => '2017',
  1385.     'leftsinglequotemark' => '2018',
  1386.     'rightsinglequotemark' => '2019',
  1387.     'singlelowquotemark' => '201a',
  1388.     'leftdoublequotemark' => '201c',
  1389.     'rightdoublequotemark' => '201d',
  1390.     'doublelowquotemark' => '201e',
  1391.     'dagger' => '2020',
  1392.     'doubledagger' => '2021',
  1393.     'enfilledcircbullet' => '2022',
  1394.     'doubbaselinedot' => '2025',
  1395.     'ellipsis' => '2026',
  1396.     'minutes' => '2032',
  1397.     'seconds' => '2033',
  1398.     'caret' => '2038',
  1399.     'guilsinglleft' => '2039',
  1400.     'guilsinglright' => '203a',
  1401.     'overline' => '203e',
  1402.     'zerosuperior' => '2070',
  1403.     'foursuperior' => '2074',
  1404.     'fivesuperior' => '2075',
  1405.     'sixsuperior' => '2076',
  1406.     'sevensuperior' => '2077',
  1407.     'eightsuperior' => '2078',
  1408.     'ninesuperior' => '2079',
  1409.     'zerosubscript' => '2080',
  1410.     'onesubscript' => '2081',
  1411.     'twosubscript' => '2082',
  1412.     'threesubscript' => '2083',
  1413.     'foursubscript' => '2084',
  1414.     'fivesubscript' => '2085',
  1415.     'sixsubscript' => '2086',
  1416.     'sevensubscript' => '2087',
  1417.     'eightsubscript' => '2088',
  1418.     'ninesubscript' => '2089',
  1419.     'EcuSign' => '20a0',
  1420.     'ColonSign' => '20a1',
  1421.     'CruzeiroSign' => '20a2',
  1422.     'FFrancSign' => '20a3',
  1423.     'LiraSign' => '20a4',
  1424.     'MillSign' => '20a5',
  1425.     'NairaSign' => '20a6',
  1426.     'PesetaSign' => '20a7',
  1427.     'RupeeSign' => '20a8',
  1428.     'WonSign' => '20a9',
  1429.     'Korean_Won' => '20a9',
  1430.     'NewSheqelSign' => '20aa',
  1431.     'DongSign' => '20ab', # Is this recognised by X ?
  1432.     'EuroSign' => '20ac',
  1433.     'Euro' => '20ac',
  1434.     'careof' => '2105',
  1435.     'numerosign' => '2116',
  1436.     'phonographcopyright' => '2117',
  1437.     'prescription' => '211e',
  1438.     'trademark' => '2122',
  1439.     'onethird' => '2153',
  1440.     'twothirds' => '2154',
  1441.     'onefifth' => '2155',
  1442.     'twofifths' => '2156',
  1443.     'threefifths' => '2157',
  1444.     'fourfifths' => '2158',
  1445.     'onesixth' => '2159',
  1446.     'fivesixths' => '215a',
  1447.     'oneeighth' => '215b',
  1448.     'threeeighths' => '215c',
  1449.     'fiveeighths' => '215d',
  1450.     'seveneighths' => '215e',
  1451.     'leftarrow' => '2190',
  1452.     'uparrow' => '2191',
  1453.     'rightarrow' => '2192',
  1454.     'downarrow' => '2193',
  1455.     'implies' => '21d2',
  1456.     'ifonlyif' => '21d4',
  1457.     'partialderivative' => '2202',
  1458.     'partdifferential' => '2202',
  1459.     'emptyset' => '2205',
  1460.     'nabla' => '2207',
  1461.     'elementof' => '2208',
  1462.     'notelementof' => '2209',
  1463.     'containsas' => '220B',
  1464.     'jot' => '2218',
  1465.     'radical' => '221a',
  1466.     'squareroot' => '221a',
  1467.     'cuberoot' => '221b',
  1468.     'fourthroot' => '221c',
  1469.     'variation' => '221d',
  1470.     'infinity' => '221e',
  1471.     'logicaland' => '2227',
  1472.     'upcaret' => '2227',
  1473.     'downcaret' => '2228',
  1474.     'logicalor' => '2228',
  1475.     'intersection' => '2229',
  1476.     'upshoe' => '2229',
  1477.     'downshoe' => '222a',
  1478.     'union' => '222a',
  1479.     'integral' => '222b',
  1480.     'dintegral' => '222c',
  1481.     'tintegral' => '222d',
  1482.     'therefore' => '2234',
  1483.     'because' => '2235',
  1484.     'approximate' => '223c',
  1485.     'similarequal' => '2243',
  1486.     'notapproxeq' => '2247',
  1487.     'approxeq' => '2248',
  1488.     'notidentical' => '2262',
  1489.     'notequal' => '2260',
  1490.     'identical' => '2261',
  1491.     'stricteq' => '2263',
  1492.     'lessthanequal' => '2264',
  1493.     'greaterthanequal' => '2265',
  1494.     'includedin' => '2282',
  1495.     'leftshoe' => '2282',
  1496.     'includes' => '2283',
  1497.     'rightshoe' => '2283',
  1498.     'lefttack' => '22a2',
  1499.     'righttack' => '22a3',
  1500.     'uptack' => '22a4',
  1501.     'downtack' => '22a5',
  1502.     'upstile' => '2308',
  1503.     'downstile' => '230a',
  1504.     'telephonerecorder' => '2315',
  1505.     'topintegral' => '2320',
  1506.     'botintegral' => '2321',
  1507.     'leftanglebracket' => '2329',
  1508.     'rightanglebracket' => '232a',
  1509.     'quad' => '2395',
  1510.     'topleftparens' => '239b',
  1511.     'botleftparens' => '239d',
  1512.     'toprightparens' => '239e',
  1513.     'botrightparens' => '23a0',
  1514.     'topleftsqbracket' => '23a1',
  1515.     'botleftsqbracket' => '23a3',
  1516.     'toprightsqbracket' => '23a4',
  1517.     'botrightsqbracket' => '23a6',
  1518.     'leftmiddlecurlybrace' => '23a8',
  1519.     'rightmiddlecurlybrace' => '23ac',
  1520.     'leftradical' => '23b7',
  1521.     'horizlinescan1' => '23ba',
  1522.     'horizlinescan3' => '23bb',
  1523.     'horizlinescan7' => '23bc',
  1524.     'horizlinescan9' => '23bd',
  1525.     'ht' => '2409',
  1526.     'lf' => '240a',
  1527.     'vt' => '240b',
  1528.     'ff' => '240c',
  1529.     'cr' => '240d',
  1530.     'nl' => '2424',
  1531.     'horizconnector' => '2500',
  1532.     'horizlinescan5' => '2500',
  1533.     'vertbar' => '2502',
  1534.     'vertconnector' => '2502',
  1535.     'topleftradical' => '250c',
  1536.     'upleftcorner' => '250c',
  1537.     'uprightcorner' => '2510',
  1538.     'lowleftcorner' => '2514',
  1539.     'lowrightcorner' => '2518',
  1540.     'leftt' => '251c',
  1541.     'rightt' => '2524',
  1542.     'topt' => '252c',
  1543.     'bott' => '2534',
  1544.     'crossinglines' => '253c',
  1545.     'checkerboard' => '2592',
  1546.     'enfilledsqbullet' => '25aa',
  1547.     'enopensquarebullet' => '25ab',
  1548.     'filledrectbullet' => '25ac',
  1549.     'openrectbullet' => '25ad',
  1550.     'emfilledrect' => '25ae',
  1551.     'emopenrectangle' => '25af',
  1552.     'filledtribulletup' => '25b2',
  1553.     'opentribulletup' => '25b3',
  1554.     'filledrighttribullet' => '25b6',
  1555.     'rightopentriangle' => '25b7',
  1556.     'filledtribulletdown' => '25bc',
  1557.     'opentribulletdown' => '25bd',
  1558.     'filledlefttribullet' => '25c0',
  1559.     'leftopentriangle' => '25c1',
  1560.     'soliddiamond' => '25c6',
  1561.     'circle' => '25cb',
  1562.     'emopencircle' => '25cb',
  1563.     'emfilledcircle' => '25cf',
  1564.     'enopencircbullet' => '25e6',
  1565.     'openstar' => '2606',
  1566.     'telephone' => '260e',
  1567.     'signaturemark' => '2613',
  1568.     'leftpointer' => '261c',
  1569.     'rightpointer' => '261e',
  1570.     'femalesymbol' => '2640',
  1571.     'malesymbol' => '2642',
  1572.     'club' => '2663',
  1573.     'heart' => '2665',
  1574.     'diamond' => '2666',
  1575.     'musicalflat' => '266d',
  1576.     'musicalsharp' => '266f',
  1577.     'checkmark' => '2713',
  1578.     'ballotcross' => '2717',
  1579.     'latincross' => '271d',
  1580.     'maltesecross' => '2720',
  1581.     'braille_blank' => '2800',
  1582.     'braille_dots_1' => '2801',
  1583.     'braille_dots_2' => '2802',
  1584.     'braille_dots_12' => '2803',
  1585.     'braille_dots_3' => '2804',
  1586.     'braille_dots_13' => '2805',
  1587.     'braille_dots_23' => '2806',
  1588.     'braille_dots_123' => '2807',
  1589.     'braille_dots_4' => '2808',
  1590.     'braille_dots_14' => '2809',
  1591.     'braille_dots_24' => '280a',
  1592.     'braille_dots_124' => '280b',
  1593.     'braille_dots_34' => '280c',
  1594.     'braille_dots_134' => '280d',
  1595.     'braille_dots_234' => '280e',
  1596.     'braille_dots_1234' => '280f',
  1597.     'braille_dots_5' => '2810',
  1598.     'braille_dots_15' => '2811',
  1599.     'braille_dots_25' => '2812',
  1600.     'braille_dots_125' => '2813',
  1601.     'braille_dots_35' => '2814',
  1602.     'braille_dots_135' => '2815',
  1603.     'braille_dots_235' => '2816',
  1604.     'braille_dots_1235' => '2817',
  1605.     'braille_dots_45' => '2818',
  1606.     'braille_dots_145' => '2819',
  1607.     'braille_dots_245' => '281a',
  1608.     'braille_dots_1245' => '281b',
  1609.     'braille_dots_345' => '281c',
  1610.     'braille_dots_1345' => '281d',
  1611.     'braille_dots_2345' => '281e',
  1612.     'braille_dots_12345' => '281f',
  1613.     'braille_dots_6' => '2820',
  1614.     'braille_dots_16' => '2821',
  1615.     'braille_dots_26' => '2822',
  1616.     'braille_dots_126' => '2823',
  1617.     'braille_dots_36' => '2824',
  1618.     'braille_dots_136' => '2825',
  1619.     'braille_dots_236' => '2826',
  1620.     'braille_dots_1236' => '2827',
  1621.     'braille_dots_46' => '2828',
  1622.     'braille_dots_146' => '2829',
  1623.     'braille_dots_246' => '282a',
  1624.     'braille_dots_1246' => '282b',
  1625.     'braille_dots_346' => '282c',
  1626.     'braille_dots_1346' => '282d',
  1627.     'braille_dots_2346' => '282e',
  1628.     'braille_dots_12346' => '282f',
  1629.     'braille_dots_56' => '2830',
  1630.     'braille_dots_156' => '2831',
  1631.     'braille_dots_256' => '2832',
  1632.     'braille_dots_1256' => '2833',
  1633.     'braille_dots_356' => '2834',
  1634.     'braille_dots_1356' => '2835',
  1635.     'braille_dots_2356' => '2836',
  1636.     'braille_dots_12356' => '2837',
  1637.     'braille_dots_456' => '2838',
  1638.     'braille_dots_1456' => '2839',
  1639.     'braille_dots_2456' => '283a',
  1640.     'braille_dots_12456' => '283b',
  1641.     'braille_dots_3456' => '283c',
  1642.     'braille_dots_13456' => '283d',
  1643.     'braille_dots_23456' => '283e',
  1644.     'braille_dots_123456' => '283f',
  1645.     'braille_dots_7' => '2840',
  1646.     'braille_dots_17' => '2841',
  1647.     'braille_dots_27' => '2842',
  1648.     'braille_dots_127' => '2843',
  1649.     'braille_dots_37' => '2844',
  1650.     'braille_dots_137' => '2845',
  1651.     'braille_dots_237' => '2846',
  1652.     'braille_dots_1237' => '2847',
  1653.     'braille_dots_47' => '2848',
  1654.     'braille_dots_147' => '2849',
  1655.     'braille_dots_247' => '284a',
  1656.     'braille_dots_1247' => '284b',
  1657.     'braille_dots_347' => '284c',
  1658.     'braille_dots_1347' => '284d',
  1659.     'braille_dots_2347' => '284e',
  1660.     'braille_dots_12347' => '284f',
  1661.     'braille_dots_57' => '2850',
  1662.     'braille_dots_157' => '2851',
  1663.     'braille_dots_257' => '2852',
  1664.     'braille_dots_1257' => '2853',
  1665.     'braille_dots_357' => '2854',
  1666.     'braille_dots_1357' => '2855',
  1667.     'braille_dots_2357' => '2856',
  1668.     'braille_dots_12357' => '2857',
  1669.     'braille_dots_457' => '2858',
  1670.     'braille_dots_1457' => '2859',
  1671.     'braille_dots_2457' => '285a',
  1672.     'braille_dots_12457' => '285b',
  1673.     'braille_dots_3457' => '285c',
  1674.     'braille_dots_13457' => '285d',
  1675.     'braille_dots_23457' => '285e',
  1676.     'braille_dots_123457' => '285f',
  1677.     'braille_dots_67' => '2860',
  1678.     'braille_dots_167' => '2861',
  1679.     'braille_dots_267' => '2862',
  1680.     'braille_dots_1267' => '2863',
  1681.     'braille_dots_367' => '2864',
  1682.     'braille_dots_1367' => '2865',
  1683.     'braille_dots_2367' => '2866',
  1684.     'braille_dots_12367' => '2867',
  1685.     'braille_dots_467' => '2868',
  1686.     'braille_dots_1467' => '2869',
  1687.     'braille_dots_2467' => '286a',
  1688.     'braille_dots_12467' => '286b',
  1689.     'braille_dots_3467' => '286c',
  1690.     'braille_dots_13467' => '286d',
  1691.     'braille_dots_23467' => '286e',
  1692.     'braille_dots_123467' => '286f',
  1693.     'braille_dots_567' => '2870',
  1694.     'braille_dots_1567' => '2871',
  1695.     'braille_dots_2567' => '2872',
  1696.     'braille_dots_12567' => '2873',
  1697.     'braille_dots_3567' => '2874',
  1698.     'braille_dots_13567' => '2875',
  1699.     'braille_dots_23567' => '2876',
  1700.     'braille_dots_123567' => '2877',
  1701.     'braille_dots_4567' => '2878',
  1702.     'braille_dots_14567' => '2879',
  1703.     'braille_dots_24567' => '287a',
  1704.     'braille_dots_124567' => '287b',
  1705.     'braille_dots_34567' => '287c',
  1706.     'braille_dots_134567' => '287d',
  1707.     'braille_dots_234567' => '287e',
  1708.     'braille_dots_1234567' => '287f',
  1709.     'braille_dots_8' => '2880',
  1710.     'braille_dots_18' => '2881',
  1711.     'braille_dots_28' => '2882',
  1712.     'braille_dots_128' => '2883',
  1713.     'braille_dots_38' => '2884',
  1714.     'braille_dots_138' => '2885',
  1715.     'braille_dots_238' => '2886',
  1716.     'braille_dots_1238' => '2887',
  1717.     'braille_dots_48' => '2888',
  1718.     'braille_dots_148' => '2889',
  1719.     'braille_dots_248' => '288a',
  1720.     'braille_dots_1248' => '288b',
  1721.     'braille_dots_348' => '288c',
  1722.     'braille_dots_1348' => '288d',
  1723.     'braille_dots_2348' => '288e',
  1724.     'braille_dots_12348' => '288f',
  1725.     'braille_dots_58' => '2890',
  1726.     'braille_dots_158' => '2891',
  1727.     'braille_dots_258' => '2892',
  1728.     'braille_dots_1258' => '2893',
  1729.     'braille_dots_358' => '2894',
  1730.     'braille_dots_1358' => '2895',
  1731.     'braille_dots_2358' => '2896',
  1732.     'braille_dots_12358' => '2897',
  1733.     'braille_dots_458' => '2898',
  1734.     'braille_dots_1458' => '2899',
  1735.     'braille_dots_2458' => '289a',
  1736.     'braille_dots_12458' => '289b',
  1737.     'braille_dots_3458' => '289c',
  1738.     'braille_dots_13458' => '289d',
  1739.     'braille_dots_23458' => '289e',
  1740.     'braille_dots_123458' => '289f',
  1741.     'braille_dots_68' => '28a0',
  1742.     'braille_dots_168' => '28a1',
  1743.     'braille_dots_268' => '28a2',
  1744.     'braille_dots_1268' => '28a3',
  1745.     'braille_dots_368' => '28a4',
  1746.     'braille_dots_1368' => '28a5',
  1747.     'braille_dots_2368' => '28a6',
  1748.     'braille_dots_12368' => '28a7',
  1749.     'braille_dots_468' => '28a8',
  1750.     'braille_dots_1468' => '28a9',
  1751.     'braille_dots_2468' => '28aa',
  1752.     'braille_dots_12468' => '28ab',
  1753.     'braille_dots_3468' => '28ac',
  1754.     'braille_dots_13468' => '28ad',
  1755.     'braille_dots_23468' => '28ae',
  1756.     'braille_dots_123468' => '28af',
  1757.     'braille_dots_568' => '28b0',
  1758.     'braille_dots_1568' => '28b1',
  1759.     'braille_dots_2568' => '28b2',
  1760.     'braille_dots_12568' => '28b3',
  1761.     'braille_dots_3568' => '28b4',
  1762.     'braille_dots_13568' => '28b5',
  1763.     'braille_dots_23568' => '28b6',
  1764.     'braille_dots_123568' => '28b7',
  1765.     'braille_dots_4568' => '28b8',
  1766.     'braille_dots_14568' => '28b9',
  1767.     'braille_dots_24568' => '28ba',
  1768.     'braille_dots_124568' => '28bb',
  1769.     'braille_dots_34568' => '28bc',
  1770.     'braille_dots_134568' => '28bd',
  1771.     'braille_dots_234568' => '28be',
  1772.     'braille_dots_1234568' => '28bf',
  1773.     'braille_dots_78' => '28c0',
  1774.     'braille_dots_178' => '28c1',
  1775.     'braille_dots_278' => '28c2',
  1776.     'braille_dots_1278' => '28c3',
  1777.     'braille_dots_378' => '28c4',
  1778.     'braille_dots_1378' => '28c5',
  1779.     'braille_dots_2378' => '28c6',
  1780.     'braille_dots_12378' => '28c7',
  1781.     'braille_dots_478' => '28c8',
  1782.     'braille_dots_1478' => '28c9',
  1783.     'braille_dots_2478' => '28ca',
  1784.     'braille_dots_12478' => '28cb',
  1785.     'braille_dots_3478' => '28cc',
  1786.     'braille_dots_13478' => '28cd',
  1787.     'braille_dots_23478' => '28ce',
  1788.     'braille_dots_123478' => '28cf',
  1789.     'braille_dots_578' => '28d0',
  1790.     'braille_dots_1578' => '28d1',
  1791.     'braille_dots_2578' => '28d2',
  1792.     'braille_dots_12578' => '28d3',
  1793.     'braille_dots_3578' => '28d4',
  1794.     'braille_dots_13578' => '28d5',
  1795.     'braille_dots_23578' => '28d6',
  1796.     'braille_dots_123578' => '28d7',
  1797.     'braille_dots_4578' => '28d8',
  1798.     'braille_dots_14578' => '28d9',
  1799.     'braille_dots_24578' => '28da',
  1800.     'braille_dots_124578' => '28db',
  1801.     'braille_dots_34578' => '28dc',
  1802.     'braille_dots_134578' => '28dd',
  1803.     'braille_dots_234578' => '28de',
  1804.     'braille_dots_1234578' => '28df',
  1805.     'braille_dots_678' => '28e0',
  1806.     'braille_dots_1678' => '28e1',
  1807.     'braille_dots_2678' => '28e2',
  1808.     'braille_dots_12678' => '28e3',
  1809.     'braille_dots_3678' => '28e4',
  1810.     'braille_dots_13678' => '28e5',
  1811.     'braille_dots_23678' => '28e6',
  1812.     'braille_dots_123678' => '28e7',
  1813.     'braille_dots_4678' => '28e8',
  1814.     'braille_dots_14678' => '28e9',
  1815.     'braille_dots_24678' => '28ea',
  1816.     'braille_dots_124678' => '28eb',
  1817.     'braille_dots_34678' => '28ec',
  1818.     'braille_dots_134678' => '28ed',
  1819.     'braille_dots_234678' => '28ee',
  1820.     'braille_dots_1234678' => '28ef',
  1821.     'braille_dots_5678' => '28f0',
  1822.     'braille_dots_15678' => '28f1',
  1823.     'braille_dots_25678' => '28f2',
  1824.     'braille_dots_125678' => '28f3',
  1825.     'braille_dots_35678' => '28f4',
  1826.     'braille_dots_135678' => '28f5',
  1827.     'braille_dots_235678' => '28f6',
  1828.     'braille_dots_1235678' => '28f7',
  1829.     'braille_dots_45678' => '28f8',
  1830.     'braille_dots_145678' => '28f9',
  1831.     'braille_dots_245678' => '28fa',
  1832.     'braille_dots_1245678' => '28fb',
  1833.     'braille_dots_345678' => '28fc',
  1834.     'braille_dots_1345678' => '28fd',
  1835.     'braille_dots_2345678' => '28fe',
  1836.     'braille_dots_12345678' => '28ff',
  1837.     'kana_comma' => '3001',
  1838.     'kana_fullstop' => '3002',
  1839.     'kana_openingbracket' => '300c',
  1840.     'kana_closingbracket' => '300d',
  1841.     'voicedsound' => '309b',
  1842.     'semivoicedsound' => '309c',
  1843.     'kana_a' => '30a1',
  1844.     'kana_A' => '30a2',
  1845.     'kana_i' => '30a3',
  1846.     'kana_I' => '30a4',
  1847.     'kana_u' => '30a5',
  1848.     'kana_U' => '30a6',
  1849.     'kana_e' => '30a7',
  1850.     'kana_E' => '30a8',
  1851.     'kana_o' => '30a9',
  1852.     'kana_O' => '30aa',
  1853.     'kana_KA' => '30ab',
  1854.     'kana_KI' => '30ad',
  1855.     'kana_KU' => '30af',
  1856.     'kana_KE' => '30b1',
  1857.     'kana_KO' => '30b3',
  1858.     'kana_SA' => '30b5',
  1859.     'kana_SHI' => '30b7',
  1860.     'kana_SU' => '30b9',
  1861.     'kana_SE' => '30bb',
  1862.     'kana_SO' => '30bd',
  1863.     'kana_TA' => '30bf',
  1864.     'kana_CHI' => '30c1',
  1865.     'kana_tsu' => '30c3',
  1866.     'kana_TSU' => '30c4',
  1867.     'kana_TE' => '30c6',
  1868.     'kana_TO' => '30c8',
  1869.     'kana_NA' => '30ca',
  1870.     'kana_NI' => '30cb',
  1871.     'kana_NU' => '30cc',
  1872.     'kana_NE' => '30cd',
  1873.     'kana_NO' => '30ce',
  1874.     'kana_HA' => '30cf',
  1875.     'kana_HI' => '30d2',
  1876.     'kana_FU' => '30d5',
  1877.     'kana_HE' => '30d8',
  1878.     'kana_HO' => '30db',
  1879.     'kana_MA' => '30de',
  1880.     'kana_MI' => '30df',
  1881.     'kana_MU' => '30e0',
  1882.     'kana_ME' => '30e1',
  1883.     'kana_MO' => '30e2',
  1884.     'kana_ya' => '30e3',
  1885.     'kana_YA' => '30e4',
  1886.     'kana_yu' => '30e5',
  1887.     'kana_YU' => '30e6',
  1888.     'kana_yo' => '30e7',
  1889.     'kana_YO' => '30e8',
  1890.     'kana_RA' => '30e9',
  1891.     'kana_RI' => '30ea',
  1892.     'kana_RU' => '30eb',
  1893.     'kana_RE' => '30ec',
  1894.     'kana_RO' => '30ed',
  1895.     'kana_WA' => '30ef',
  1896.     'kana_WO' => '30f2',
  1897.     'kana_N' => '30f3',
  1898.     'kana_conjunctive' => '30fb',
  1899.     'kana_middledot' => '30fb', # Is this recognised by X ?
  1900.     'prolongedsound' => '30fc',
  1901.     'Hangul_Kiyeog' => '3131',
  1902.     'Hangul_SsangKiyeog' => '3132',
  1903.     'Hangul_KiyeogSios' => '3133',
  1904.     'Hangul_Nieun' => '3134',
  1905.     'Hangul_NieunJieuj' => '3135',
  1906.     'Hangul_NieunHieuh' => '3136',
  1907.     'Hangul_Dikeud' => '3137',
  1908.     'Hangul_SsangDikeud' => '3138',
  1909.     'Hangul_Rieul' => '3139',
  1910.     'Hangul_RieulKiyeog' => '313a',
  1911.     'Hangul_RieulMieum' => '313b',
  1912.     'Hangul_RieulPieub' => '313c',
  1913.     'Hangul_RieulSios' => '313d',
  1914.     'Hangul_RieulTieut' => '313e',
  1915.     'Hangul_RieulPhieuf' => '313f',
  1916.     'Hangul_RieulHieuh' => '3140',
  1917.     'Hangul_Mieum' => '3141',
  1918.     'Hangul_Pieub' => '3142',
  1919.     'Hangul_SsangPieub' => '3143',
  1920.     'Hangul_PieubSios' => '3144',
  1921.     'Hangul_Sios' => '3145',
  1922.     'Hangul_SsangSios' => '3146',
  1923.     'Hangul_Ieung' => '3147',
  1924.     'Hangul_Jieuj' => '3148',
  1925.     'Hangul_SsangJieuj' => '3149',
  1926.     'Hangul_Cieuc' => '314a',
  1927.     'Hangul_Khieuq' => '314b',
  1928.     'Hangul_Tieut' => '314c',
  1929.     'Hangul_Phieuf' => '314d',
  1930.     'Hangul_Hieuh' => '314e',
  1931.     'Hangul_A' => '314f',
  1932.     'Hangul_AE' => '3150',
  1933.     'Hangul_YA' => '3151',
  1934.     'Hangul_YAE' => '3152',
  1935.     'Hangul_EO' => '3153',
  1936.     'Hangul_E' => '3154',
  1937.     'Hangul_YEO' => '3155',
  1938.     'Hangul_YE' => '3156',
  1939.     'Hangul_O' => '3157',
  1940.     'Hangul_WA' => '3158',
  1941.     'Hangul_WAE' => '3159',
  1942.     'Hangul_OE' => '315a',
  1943.     'Hangul_YO' => '315b',
  1944.     'Hangul_U' => '315c',
  1945.     'Hangul_WEO' => '315d',
  1946.     'Hangul_WE' => '315e',
  1947.     'Hangul_WI' => '315f',
  1948.     'Hangul_YU' => '3160',
  1949.     'Hangul_EU' => '3161',
  1950.     'Hangul_YI' => '3162',
  1951.     'Hangul_I' => '3163',
  1952.     'Hangul_RieulYeorinHieuh' => '316d',
  1953.     'Hangul_SunkyeongeumMieum' => '3171',
  1954.     'Hangul_SunkyeongeumPieub' => '3178',
  1955.     'Hangul_PanSios' => '317f',
  1956.     'Hangul_KkogjiDalrinIeung' => '3181',
  1957.     'Hangul_SunkyeongeumPhieuf' => '3184',
  1958.     'Hangul_YeorinHieuh' => '3186',
  1959.     'Hangul_AraeA' => '318d',
  1960.     'Hangul_AraeAE' => '318e',
  1961. # Keypad keys
  1962.     'KP_Multiply' => 'KP_Multiply',
  1963.     'KP_Add' => 'KP_Add',
  1964.     'KP_Seprator' => 'KP_Comma', # Is this recognised by X ?
  1965.     'KP_Separator' => 'KP_Comma',
  1966.     'KP_Subtract' => 'KP_Subtract',
  1967.     'KP_Decimal' => 'KP_Period',
  1968.     'KP_Divide' => 'KP_Divide',
  1969.     'KP_0' => 'KP_0',
  1970.     'KP_1' => 'KP_1',
  1971.     'KP_2' => 'KP_2',
  1972.     'KP_3' => 'KP_3',
  1973.     'KP_4' => 'KP_4',
  1974.     'KP_5' => 'KP_5',
  1975.     'KP_6' => 'KP_6',
  1976.     'KP_7' => 'KP_7',
  1977.     'KP_8' => 'KP_8',
  1978.     'KP_9' => 'KP_9',
  1979.     'KP_Enter' => 'KP_Enter',
  1980. # Keypad keys (alternate level)
  1981.     'KP_Home' => 'KP_7',
  1982.     'KP_Left' => 'KP_4',
  1983.     'KP_Up' => 'KP_8',
  1984.     'KP_Right' => 'KP_6',
  1985.     'KP_Down' => 'KP_2',
  1986.     'KP_Prior' => 'KP_9',
  1987.     'KP_Page_Up' => 'KP_9',
  1988.     'KP_Next' => 'KP_3',
  1989.     'KP_Page_Down' => 'KP_3',
  1990.     'KP_End' => 'KP_1',
  1991.     'KP_Begin' => 'VoidSymbol', # What does correspond to this?
  1992.     'KP_Insert' => 'KP_0',
  1993.     'KP_Delete' => 'VoidSymbol', # has to be 'KP_Period' or 'KP_Decimal'
  1994. # Keypad keys with missing support in the kernel
  1995.     'KP_Space' => 'space',
  1996.     'KP_Equal' => 'equal',
  1997.     'KP_Tab' => 'Tab',
  1998.     'KP_F1' => 'F1',
  1999.     'KP_F2' => 'F2',
  2000.     'KP_F3' => 'F3',
  2001.     'KP_F4' => 'F4',
  2002. # Dead symbols
  2003.     'dead_grave' => 'dead_grave',
  2004.     'SunFA_Grave' => 'dead_grave', # Is this recognised by X ?
  2005.     'dead_acute' => 'dead_acute',
  2006.     'SunFA_Acute' => 'dead_acute', # Is this recognised by X ?
  2007.     'dead_circumflex' => 'dead_circumflex',
  2008.     'SunFA_Circum' => 'dead_circumflex', # Is this recognised by X ?
  2009.     'dead_tilde' => 'dead_tilde',
  2010.     'SunFA_Tilde' => 'dead_tilde',
  2011.     'dead_breve' => 'dead_breve',
  2012.     'dead_diaeresis' => 'dead_diaeresis',
  2013.     'SunFA_Diaeresis' => 'dead_diaeresis', # Is this recognised by X ?
  2014.     'dead_doubleacute' => 'dead_doubleacute',
  2015.     'dead_caron' => 'dead_caron',
  2016.     'dead_cedilla' => 'dead_cedilla',
  2017.     'SunFA_Cedilla' => 'dead_cedilla', # Is this recognised by X ?
  2018.     'dead_ogonek' => 'dead_ogonek',
  2019. # Dead symbols with no support in the kernel
  2020.     'dead_macron' => '005f',         # underscore
  2021.     'dead_abovedot' => '002e',       # period
  2022.     'dead_abovering' => '002a',      # asterisk
  2023.     'dead_stroke' => '002d',         # hyphen
  2024.     'dead_belowdot' => '0323',       # ???? Vietnamese
  2025.     'dead_hook' => '0309',           # ???? Vietnamese
  2026.     'dead_iota' => '03b9',           # ???? Greek
  2027.     'dead_horn' => '031b',           # ???? Greek
  2028.     'dead_psili' => 'VoidSymbol',    # ???? Greek
  2029.     'dead_dasia' => 'VoidSymbol',    # ???? Greek
  2030. # Modifiers
  2031.     'Multi_key' => 'Compose',
  2032.     'Mode_switch' => 'ShiftL',
  2033.     'script_switch' => 'VoidSymbol',
  2034.     'Shift_L' => 'Shift',
  2035.     'Shift_R' => 'Shift',
  2036.     'Control_L' => 'Control',
  2037.     'Control_R' => 'Control',
  2038.     'Caps_Lock' => 'Caps_Lock',
  2039.     'Shift_Lock' => 'Shift_Lock',
  2040.     'Meta_L' => 'Alt',
  2041.     'Meta_R' => 'Alt',
  2042.     'Alt_L' => 'Alt',
  2043.     'Alt_R' => 'Alt',
  2044.     'Super_L' => 'Alt',
  2045.     'Super_R' => 'Alt',
  2046.     'Hyper_L' => 'Alt',
  2047.     'Hyper_R' => 'Alt',
  2048.     'ISO_Lock' => 'Caps_Lock',
  2049.     'ISO_Level2_Latch' => 'Shift',
  2050.     'ISO_Level3_Shift' => 'AltGr',
  2051.     'ISO_Level3_Latch' => 'AltGr',
  2052.     'ISO_Level3_Lock' => 'AltGr_Lock',
  2053.     'ISO_Group_Shift' => 'ShiftL',
  2054.     'ISO_Group_Latch' => 'ShiftL',
  2055.     'ISO_Group_Lock' => 'ShiftL_Lock',
  2056.     'ISO_Next_Group' => 'ShiftL_Lock',
  2057.     'ISO_Next_Group_Lock' => 'ShiftL_Lock',
  2058.     'ISO_Prev_Group' => 'ShiftL_Lock',
  2059.     'ISO_Prev_Group_Lock' => 'ShiftL_Lock',
  2060.     'ISO_First_Group' => 'ShiftL_Lock',
  2061.     'ISO_First_Group_Lock' => 'ShiftL_Lock',
  2062.     'ISO_Last_Group' => 'ShiftL_Lock',
  2063.     'ISO_Last_Group_Lock' => 'ShiftL_Lock',
  2064. # Other symbols
  2065.     'NoAction' => 'NoSymbol', # Is this recognised by X ?
  2066.     'nosymbol' => 'NoSymbol', # Is this recognised by X ?
  2067.     'Nosymbol' => 'NoSymbol', # Is this recognised by X ?
  2068.     'noSymbol' => 'NoSymbol', # Is this recognised by X ?
  2069.     'NoSymbol' => 'NoSymbol',
  2070.     'any' => 'NoSymbol', # Is this recognised by X ?
  2071.     'VoidSymbol' => 'VoidSymbol',
  2072.     'voidsymbol' => 'VoidSymbol', # Is this recognised by X ?
  2073.     'ISO_Left_Tab' => 'Tab',
  2074.     'Clear' => 'VoidSymbol',
  2075.     'Pause' => 'Pause',
  2076.     'Scroll_Lock' => 'Scroll_Lock',
  2077.     'Sys_Req' => 'VoidSymbol',
  2078.     'Delete' => 'Remove',
  2079.     'Codeinput' => 'VoidSymbol',
  2080.     'SingleCandidate' => 'VoidSymbol',
  2081.     'MultipleCandidate' => 'VoidSymbol',
  2082.     'PreviousCandidate' => 'VoidSymbol',
  2083.     'Home' => 'Home',
  2084.     'Left' => 'Left',
  2085.     'Up' => 'Up',
  2086.     'Right' => 'Right',
  2087.     'Down' => 'Down',
  2088.     'Prior' => 'Prior',
  2089.     'Page_Up' => 'PageUp',
  2090.     'Next' => 'Next',
  2091.     'Page_Down' => 'PageDown',
  2092.     'End' => 'End',
  2093.     'Begin' => 'VoidSymbol',
  2094.     'Select' => 'Select',
  2095.     'Print' => 'VoidSymbol',
  2096.     'Execute' => 'VoidSymbol',
  2097.     'Insert' => 'Insert',
  2098.     'Undo' => 'VoidSymbol',
  2099.     'Redo' => 'VoidSymbol',
  2100.     'Menu' => 'VoidSymbol',
  2101.     'Find' => 'Find',
  2102.     'Cancel' => 'VoidSymbol',
  2103.     'Help' => 'Help',
  2104.     'Break' => 'Pause',
  2105.     'Num_Lock' => 'Num_Lock',
  2106.     'F1' => 'F1',
  2107.     'F2' => 'F2',
  2108.     'F3' => 'F3',
  2109.     'F4' => 'F4',
  2110.     'F5' => 'F5',
  2111.     'F6' => 'F6',
  2112.     'F7' => 'F7',
  2113.     'F8' => 'F8',
  2114.     'F9' => 'F9',
  2115.     'F10' => 'F10',
  2116.     'F11' => 'F11',
  2117.     'L1' => 'F11',
  2118.     'F12' => 'F12',
  2119.     'L2' => 'F12',
  2120.     'F13' => 'F13',
  2121.     'L3' => 'F13',
  2122.     'F14' => 'F14',
  2123.     'L4' => 'F14',
  2124.     'F15' => 'F15',
  2125.     'L5' => 'F15',
  2126.     'F16' => 'F16',
  2127.     'L6' => 'F16',
  2128.     'F17' => 'F17',
  2129.     'L7' => 'F17',
  2130.     'F18' => 'F18',
  2131.     'L8' => 'F18',
  2132.     'F19' => 'F19',
  2133.     'L9' => 'F19',
  2134.     'F20' => 'F20',
  2135.     'L10' => 'F20',
  2136.     'F21' => 'F21',
  2137.     'R1' => 'F21',
  2138.     'F22' => 'F22',
  2139.     'R2' => 'F22',
  2140.     'F23' => 'F23',
  2141.     'R3' => 'F23',
  2142.     'F24' => 'F24',
  2143.     'R4' => 'F24',
  2144.     'F25' => 'F25',
  2145.     'R5' => 'F25',
  2146.     'F26' => 'F26',
  2147.     'R6' => 'F26',
  2148.     'F27' => 'F27',
  2149.     'R7' => 'F27',
  2150.     'F28' => 'F28',
  2151.     'R8' => 'F28',
  2152.     'F29' => 'F29',
  2153.     'R9' => 'F29',
  2154.     'F30' => 'F30',
  2155.     'R10' => 'F30',
  2156.     'F31' => 'F31',
  2157.     'R11' => 'F31',
  2158.     'F32' => 'F32',
  2159.     'R12' => 'F32',
  2160.     'F33' => 'F33',
  2161.     'R13' => 'F33',
  2162.     'F34' => 'F34',
  2163.     'R14' => 'F34',
  2164.     'F35' => 'F35',
  2165.     'R15' => 'F35',
  2166.     'Terminate_Server' => 'VoidSymbol',
  2167.     'Pointer_EnableKeys' => 'VoidSymbol',
  2168.     'XF86_Switch_VT_1' => 'Console_1',
  2169.     'XF86_Switch_VT_2' => 'Console_2',
  2170.     'XF86_Switch_VT_3' => 'Console_3',
  2171.     'XF86_Switch_VT_4' => 'Console_4',
  2172.     'XF86_Switch_VT_5' => 'Console_5',
  2173.     'XF86_Switch_VT_6' => 'Console_6',
  2174.     'XF86_Switch_VT_7' => 'Console_7',
  2175.     'XF86_Switch_VT_8' => 'Console_8',
  2176.     'XF86_Switch_VT_9' => 'Console_9',
  2177.     'XF86_Switch_VT_10' => 'Console_10',
  2178.     'XF86_Switch_VT_11' => 'Console_11',
  2179.     'XF86_Switch_VT_12' => 'Console_12',
  2180.     'XF86_ClearGrab' => 'VoidSymbol',
  2181.     'XF86_Ungrab' => 'VoidSymbol',
  2182.     'XF86_Next_VMode' => 'VoidSymbol',
  2183.     'XF86_Prev_VMode' => 'VoidSymbol',
  2184.     'XF86Copy' => 'VoidSymbol',
  2185.     'XF86Cut' => 'VoidSymbol',
  2186.     'XF86Paste' => 'VoidSymbol',
  2187.     'XF86AudioLowerVolume' => 'VoidSymbol',
  2188.     'XF86AudioRaiseVolume' => 'VoidSymbol',
  2189.     'XF86AudioMute' => 'VoidSymbol',
  2190.     'XF86PowerOff' => 'VoidSymbol',
  2191.     'braille_dot_1' => 'Brl_dot1',
  2192.     'braille_dot_2' => 'Brl_dot2',
  2193.     'braille_dot_3' => 'Brl_dot3',
  2194.     'braille_dot_4' => 'Brl_dot4',
  2195.     'braille_dot_5' => 'Brl_dot5',
  2196.     'braille_dot_6' => 'Brl_dot6',
  2197.     'braille_dot_7' => 'Brl_dot7',
  2198.     'braille_dot_8' => 'Brl_dot8',
  2199.     'braille_dot_9' => 'Brl_dot9',
  2200.     'braille_dot_10' => 'Brl_dot10',
  2201. # I do not know the Unicodes of these
  2202.     '0x1000' => 'VoidSymbol', # Special symbol for X or syntax error?
  2203.     '0x13a4' => 'VoidSymbol', # Special symbol for X or syntax error?
  2204.     '0xfe11' => 'VoidSymbol', # Special symbol for X or syntax error?
  2205.     'leftcaret' => 'VoidSymbol', # Is this recognised by X ?
  2206.     'guj_rra' => 'VoidSymbol', # Is this recognised by X ?
  2207.     'guj_nnna' => 'VoidSymbol', # Is this recognised by X ?
  2208.     'guj_llla' => 'VoidSymbol', # Is this recognised by X ?
  2209.     'gur_visarga' => 'VoidSymbol', # Is this recognised by X ?
  2210.     'gur_v_r' => 'VoidSymbol', # Is this recognised by X ?
  2211.     'gur_v_r_s' => 'VoidSymbol', # Is this recognised by X ?
  2212.     'Eisu_toggle' => 'VoidSymbol', # Is this recognised by X ?
  2213.     'Zenkaku_Hankaku' => 'VoidSymbol', # Is this recognised by X ?
  2214.     'Kanji' => 'VoidSymbol', # Is this recognised by X ?
  2215.     'Hangul' => 'VoidSymbol', # Is this recognised by X ?
  2216.     'Hangul_Hanja' => 'VoidSymbol', # Is this recognised by X ?
  2217. # XFree86 does not recognise these
  2218.     'SunAudioLowerVolume' => 'VoidSymbol',
  2219.     'SunAudioRaiseVolume' => 'VoidSymbol',
  2220.     'SunAudioMute' => 'VoidSymbol',
  2221.     'SunCopy' => 'VoidSymbol',
  2222.     'SunCut' => 'VoidSymbol',
  2223.     'SunPaste' => 'VoidSymbol',
  2224.     'SunAgain' => 'VoidSymbol',
  2225.     'SunUndo' => 'VoidSymbol',
  2226.     'SunFind' => 'VoidSymbol',
  2227.     'SunStop' => 'VoidSymbol',
  2228.     'SunF36' => 'VoidSymbol',
  2229.     'SunF37' => 'VoidSymbol',
  2230.     'SunFront' => 'VoidSymbol',
  2231.     'SunOpen' => 'VoidSymbol',
  2232.     'SunPowerSwitch' => 'VoidSymbol',
  2233.     'SunPowerSwitchShift' => 'VoidSymbol',
  2234.     'SunProps' => 'VoidSymbol',
  2235.     'SunSys_Req' => 'VoidSymbol',
  2236.     'SunVideoDegauss' => 'VoidSymbol',
  2237.     'SunVideoLowerBrightness' => 'VoidSymbol',
  2238.     'SunVideoRaiseBrightness' => 'VoidSymbol',
  2239. );
  2240.  
  2241. if ($compact) {
  2242.     $xkbsym_table{'Mode_switch'} = 'AltGr';
  2243.     $xkbsym_table{'ISO_Group_Shift'} = 'AltGr';
  2244.     $xkbsym_table{'ISO_Group_Latch'} = 'AltGr';
  2245.     $xkbsym_table{'ISO_Group_Lock'} = 'AltGr_Lock';
  2246.     $xkbsym_table{'ISO_Next_Group'} = 'AltGr_Lock';
  2247.     $xkbsym_table{'ISO_Next_Group_Lock'} = 'AltGr_Lock';
  2248.     $xkbsym_table{'ISO_Prev_Group'} = 'AltGr_Lock';
  2249.     $xkbsym_table{'ISO_Prev_Group_Lock'} = 'AltGr_Lock';
  2250.     $xkbsym_table{'ISO_First_Group'} = 'AltGr_Lock';
  2251.     $xkbsym_table{'ISO_First_Group_Lock'} = 'AltGr_Lock';
  2252.     $xkbsym_table{'ISO_Last_Group'} = 'AltGr_Lock';
  2253.     $xkbsym_table{'ISO_Last_Group_Lock'} = 'AltGr_Lock';
  2254. }
  2255.  
  2256. my @controlsyms;
  2257. my @metasyms;
  2258. my @metacontrolsyms;
  2259.  
  2260. {
  2261.     my %controlsyms_hash = (
  2262.     '@' => 'nul',
  2263.     'h' => 'BackSpace',
  2264.     'i' => 'Tab',
  2265.     'j' => 'Linefeed',
  2266.     '[' => 'Escape',
  2267.     '\\' => 'Control_backslash',
  2268.     ']' => 'Control_bracketright',
  2269.     '^' => 'Control_asciicircum',
  2270.     '_' => 'Control_underscore',
  2271.     chr(0x08) => 'BackSpace',
  2272.     chr(0x09) => 'Tab',
  2273.     chr(0x0a) => 'Linefeed',
  2274.     chr(0x0d) => 'Control_m',
  2275.     chr(0x1b) => 'Escape',
  2276.     chr(0x7f) => 'BackSpace', # instead of 'Delete'
  2277. # The following are Linux specific
  2278.     '2' => 'nul',
  2279.     '3' => 'Escape',
  2280.     '4' => 'Control_backslash',
  2281.     '5' => 'Control_bracketright',
  2282.     '6' => 'Control_asciicircum',
  2283.     '7' => 'Control_underscore',
  2284.     '8' => 'Delete',
  2285.     '\'' => 'Control_g', # apostrophe
  2286.     '`' => 'nul', # grave
  2287.     '.' => 'Compose',
  2288.     '?' => 'Delete',
  2289.     ' ' => 'nul',
  2290.     );
  2291.     for my $code (0 .. 255) {
  2292.     my $sym = chr ((0x41 <= $code && 0x5a >= $code) ? $code + 0x20 : $code);
  2293.     if (defined (my $special = $controlsyms_hash{$sym})) {
  2294.         $controlsyms[$code + 1] = $special;
  2295.     } elsif (0x40 <= $code && 0x5f >= $code      
  2296.         || 0x61 <= $code && 0x7a >= $code) {
  2297.         $controlsyms[$code + 1] = "Control_". $sym;
  2298.     } else {
  2299.         $controlsyms[$code + 1] = 'VoidSymbol';
  2300.     }
  2301.     }
  2302.     $controlsyms[0] = 'NoSymbol';
  2303.  
  2304.     my %metasyms_hash = (
  2305.     ' ' => 'space',
  2306.     '`' => 'grave',
  2307.     '^' => 'asciicircum',
  2308.     '~' => 'asciitilde',
  2309.     '<' => 'less',
  2310.     '=' => 'equal',
  2311.     '>' => 'greater',
  2312.     '|' => 'bar',
  2313.     '_' => 'underscore',
  2314.     '-' => 'minus',
  2315.     ',' => 'comma',
  2316.     ';' => 'semicolon',
  2317.     ':' => 'colon',
  2318.     '!' => 'exclam',
  2319.     '?' => 'question',
  2320.     '/' => 'slash',
  2321.     '.' => 'period',
  2322.     '\'' => 'apostrophe',
  2323.     '"' => 'quotedbl',
  2324.     '(' => 'parenleft',
  2325.     ')' => 'parenright',
  2326.     '[' => 'bracketleft',
  2327.     ']' => 'bracketright',
  2328.     '{' => 'braceleft',
  2329.     '}' => 'braceright',
  2330.     '@' => 'at',
  2331.     '$' => 'dollar',
  2332.     '*' => 'asterisk',
  2333.     '\\' => 'backslash',
  2334.     '&' => 'ampersand',
  2335.     '#' => 'numbersign',
  2336.     '%' => 'percent',
  2337.     '+' => 'plus',
  2338.     '0' => 'zero',
  2339.     '1' => 'one',
  2340.     '2' => 'two',
  2341.     '3' => 'three',
  2342.     '4' => 'four',
  2343.     '5' => 'five',
  2344.     '6' => 'six',
  2345.     '7' => 'seven',
  2346.     '8' => 'eight',
  2347.     '9' => 'nine',
  2348.     chr(0x08) => 'BackSpace',
  2349.     chr(0x09) => 'Tab',
  2350.     chr(0x0a) => 'Linefeed',
  2351.     chr(0x0d) => 'Control_m',
  2352.     chr(0x1b) => 'Escape',
  2353.     chr(0x7f) => 'Delete',
  2354.     );
  2355.     
  2356.     for my $code (0 .. 255) {
  2357.     my $sym = chr($code);
  2358.     if (defined (my $special = $metasyms_hash{$sym})) {
  2359.         $sym = $special;
  2360.     }
  2361.     $metasyms[$code + 1] = "Meta_". $sym;
  2362.     }
  2363.  
  2364.     $metasyms[0] = 'NoSymbol';
  2365.  
  2366.     for my $code (1 .. 256) {
  2367.     my $control = $controlsyms[$code];
  2368.     if ($control eq 'Compose') {
  2369.         $metacontrolsyms[$code] = 'Compose';
  2370.     } elsif ($control eq 'NoSymbol') {
  2371.         $metacontrolsyms[$code] = 'NoSymbol';
  2372.     } elsif ($control eq 'VoidSymbol') {
  2373.         $metacontrolsyms[$code] = 'VoidSymbol';
  2374.     } else {
  2375.         $metacontrolsyms[$code] = 'Meta_'. $control;
  2376.     }
  2377.     }
  2378.  
  2379.     $metacontrolsyms[0] = 'NoSymbol';
  2380.  
  2381. }
  2382.  
  2383. ############ GLOBAL FUNCTIONS #########################################
  2384.  
  2385. # Looks for $_[0] in the known directories and returns ready to use
  2386. # file name
  2387. sub xfilename {
  2388.     my $file = $_[0];
  2389.     (my $base = $file) =~ s/.*\/(.+)/$1/;
  2390.     for my $dir (@xdirs) {
  2391.     if (-f "$dir/$file") {
  2392.         return "$dir/$file";
  2393.     }
  2394.     if (-f "$dir/$base") {
  2395.         return "$dir/$base";
  2396.     }
  2397.     }
  2398.     die "$0: Can not find file \"$file\" in any known directory\n";
  2399. }
  2400.  
  2401. ########### READ THE RULES FILE #######################################
  2402.  
  2403. # The string $_[0] matches the pattern $_[1]. 
  2404. # The pattern may be "*", a variable name, or a plain string.
  2405. # If the string is 'OPTIONS' then match the pattern against any of the
  2406. # options from @options.
  2407. sub matches_pattern {
  2408.     my ($string, $pattern) = @_;
  2409.     if ($string eq 'OPTIONS') {
  2410.     for my $option (@options) {
  2411.         next if ($option eq '');
  2412.         if ($pattern eq $option) {
  2413.         return 1;
  2414.         }
  2415.     }
  2416.     } else {
  2417.     if ($pattern eq '*') {
  2418.         return $string ne '';
  2419.     }
  2420.     if ($pattern =~ /^\$([a-zA-Z0-9]+)$/) {
  2421.         for my $member (@{$rules_variables{$1}}) {
  2422.         if ($string eq $member) {
  2423.             return 1;
  2424.         }
  2425.         }
  2426.         return 0;
  2427.     }
  2428.     if ($string eq $pattern) {
  2429.         return 1;
  2430.     }
  2431.     }
  2432.     return 0;
  2433. }
  2434.  
  2435. if (@layouts) {
  2436.     for my $i (0 .. $#layouts) {
  2437.     if (! defined $variants[$i]) {
  2438.         $variants[$i] = '';
  2439.     }
  2440.     }
  2441.     my $rules_keycodes;
  2442.     my $rules_symbols;
  2443.     open (RULES, xfilename ("rules/$rules"))
  2444.     or die "$0: ". xfilename ("rules/$rules") .": $!\n";
  2445.     my $oldline = '';
  2446.     my @antecedents;
  2447.     my @consequents;
  2448.     my $match_found = 0;
  2449.     while (<RULES>) {
  2450.     next if (/^\s*\/\//);
  2451.     next if (/^\s*$/);
  2452.     chomp;
  2453.     s/^\s*//;
  2454.     s/\s+/ /g;
  2455.     if ($oldline) {
  2456.         $_ = $oldline . $_;
  2457.         $oldline = '';
  2458.     }
  2459.     if (s/\\$/ /) {
  2460.         $oldline = $_;
  2461.         next;
  2462.     }
  2463.     if (/^! ?\$([a-zA-Z0-9]+) ?= ?(.+)$/) {
  2464.         $rules_variables{$1} = [ split ' ', $2 ];
  2465.         next;
  2466.     }
  2467.     if (/^! ?(.+)= ?(.+)$/) {
  2468.         @antecedents = split ' ', $1;
  2469.         @consequents = split ' ', $2;
  2470.         foreach my $i (0 .. $#antecedents) {
  2471.         if ($antecedents[$i] eq 'model') {
  2472.             $antecedents[$i] = $model;
  2473.         } elsif ($antecedents[$i] eq 'layout' && @layouts == 1) {
  2474.             $antecedents[$i] = $layouts[0];
  2475.         } elsif ($antecedents[$i] =~ /layout\[([1-4])\]/) {
  2476.             if (@layouts > 1) {
  2477.             $antecedents[$i] = $layouts[$1 - 1];
  2478.             } else {
  2479.             $antecedents[$i] = '';
  2480.             }
  2481.         } elsif ($antecedents[$i] eq 'variant' && @variants == 1) {
  2482.             $antecedents[$i] = $variants[0];
  2483.         } elsif ($antecedents[$i] =~ /variant\[([1-4])\]/) {
  2484.             if (@variants > 1) {
  2485.             $antecedents[$i] = $variants[$1 - 1];
  2486.             } else {
  2487.             $antecedents[$i] = '';
  2488.             }
  2489.         } elsif ($antecedents[$i] eq 'option') {
  2490.             $antecedents[$i] = 'OPTIONS';
  2491.         } elsif ($antecedents[$i] eq 'layout'
  2492.              || $antecedents[$i] eq 'variant') {
  2493.             $antecedents[$i] = '';
  2494.         } else {
  2495.             die "Unknown name $antecedents[$i]\n";
  2496.         }
  2497.         if (! defined $antecedents[$i]) {
  2498.             $antecedents[$i] = '';
  2499.         }
  2500.         }
  2501.         $match_found = 0;
  2502.         next;
  2503.     }
  2504.     if (/^(.+)= ?(.+)$/) {
  2505.         next if ($match_found);
  2506.         my @antecedent_patterns = split ' ', $1;
  2507.         my $consequent_str = $2;
  2508.         @antecedent_patterns == @antecedents 
  2509.         or die "Bad number of antecedents";
  2510.         my $matches = 1;
  2511.         for my $i (0 .. $#antecedents) {
  2512.         if (! matches_pattern ($antecedents[$i], 
  2513.                        $antecedent_patterns[$i])) {
  2514.             $matches = 0;
  2515.             last;
  2516.         }
  2517.         }
  2518.         if ($matches) {
  2519.         $match_found = $antecedents[0] ne 'OPTIONS';
  2520.         my @consequent_values = split ' ', $2;
  2521.         @consequent_values == @consequents
  2522.             or die sprintf ("Bad number of consequents: %d != %d",
  2523.                     scalar (@consequent_values),
  2524.                     scalar (@consequents));
  2525.         for my $i (0 .. $#consequents) {
  2526.             $consequent_values[$i] =~ s/%\(/\(%/g;
  2527.             $consequent_values[$i] =~ s/%_/_%/g;
  2528.             $consequent_values[$i] =~ s/%m/$model/g;
  2529.             $consequent_values[$i] =~ s/%l\[1\]/$layouts[0]/g;
  2530.             $consequent_values[$i] =~ s/%l\[2\]/$layouts[1]/g;
  2531.             $consequent_values[$i] =~ s/%l\[3\]/$layouts[2]/g;
  2532.             $consequent_values[$i] =~ s/%l\[4\]/$layouts[3]/g;
  2533.             $consequent_values[$i] =~ s/%l/$layouts[0]/g;
  2534.             $consequent_values[$i] =~ s/%v\[1\]/$variants[0]/g;
  2535.             $consequent_values[$i] =~ s/%v\[2\]/$variants[1]/g;
  2536.             $consequent_values[$i] =~ s/%v\[3\]/$variants[2]/g;
  2537.             $consequent_values[$i] =~ s/%v\[4\]/$variants[3]/g;
  2538.             $consequent_values[$i] =~ s/%v/$variants[0]/g;
  2539.             $consequent_values[$i] =~ s/\(\)//g;
  2540.             if ($consequent_values[$i] =~ /^\+/) {
  2541.             if ($consequents[$i] eq 'keycodes') {
  2542.                 $rules_keycodes = $rules_keycodes .
  2543.                 $consequent_values[$i];
  2544.             } elsif ($consequents[$i] eq 'symbols') {
  2545.                 $rules_symbols = $rules_symbols .
  2546.                 $consequent_values[$i];
  2547.             }
  2548.             } else {
  2549.             if ($consequents[$i] eq 'keycodes') {
  2550.                 if (! $rules_keycodes) {
  2551.                 $rules_keycodes = $consequent_values[$i];
  2552.                 }
  2553.             } elsif ($consequents[$i] eq 'symbols') {
  2554.                 if (! $rules_symbols) {
  2555.                 $rules_symbols = $consequent_values[$i];
  2556.                 }
  2557.             }
  2558.             }
  2559.         }
  2560.         }
  2561.         next;
  2562.     }    
  2563.     die "Syntax error in the rules file: $_\n";
  2564.     }
  2565.     close RULES;
  2566.  
  2567.     if ($verbosity >= 1) {
  2568.     print STDERR  "Acording to the rules file:\n"
  2569.         ." keycodes = $rules_keycodes\n"
  2570.         ." symbols = $rules_symbols\n";
  2571.     }
  2572.  
  2573.     if (! $keycodes) {
  2574.     $keycodes = $rules_keycodes;
  2575.     }
  2576.     if (! $symbols) {
  2577.     $symbols = $rules_symbols;
  2578.     }
  2579. }
  2580.  
  2581. if (! $keycodes) {
  2582.     die "$0: No keycodes, nor layout specified\n";
  2583. }
  2584. if (! $symbols) {
  2585.     die "$0: No symbols, nor layout specified\n";
  2586. }
  2587.  
  2588. ########### COMPUTE ARCH ###########################################
  2589.  
  2590. if ($keycodes =~ /(^|\+|\|)macintosh\(old\)($|\+|\|)/) {
  2591.     $arch = 'macintosh';
  2592. } elsif ($keycodes =~ /(^|\+|\|)ataritt(\([^\)]*\))?($|\+|\|)/) {
  2593.     $arch = 'ataritt';
  2594. } elsif ($keycodes =~ /(^|\+|\|)amiga(\([^\)]*\))?($|\+|\|)/) {
  2595.     $arch = 'amiga';
  2596. } elsif ($keycodes =~ /(^|\+|\|)sun(\(type[45][^\)]*\))?($|\+|\|)/) {
  2597.     $arch = 'sun';
  2598. }
  2599.  
  2600. ########### READ ACM ###############################################
  2601.  
  2602. if ($charmap) {
  2603.     for my $acmfile ("${charmap}", "${charmap}.gz",
  2604.              "${charmap}.acm", "${charmap}.acm.gz",
  2605.              "/usr/share/consoletrans/${charmap}",
  2606.              "/usr/share/consoletrans/${charmap}.gz",
  2607.              "/usr/share/consoletrans/${charmap}.acm",
  2608.              "/usr/share/consoletrans/${charmap}.acm.gz",
  2609.              "acm/${charmap}.acm") {
  2610.     if (-f $acmfile) {
  2611.         $acm = $acmfile;
  2612.         last;
  2613.     }
  2614.     }
  2615.     (-f $acm) or die "$0: no ACM for ${charmap} exists\n";
  2616.     if ($acm =~ /gz$/) {
  2617.     open (ACM, '-|:utf8', "zcat $acm") or die "$0: $acm: $!\n";
  2618.     } else {
  2619.     open (ACM, '<:utf8', $acm) or die "$0: $acm: $!\n";
  2620.     }
  2621.     while (<ACM>) {
  2622.     s/\#.*//;
  2623.     chomp;
  2624.     next unless (/[^\s]/);
  2625.     if (/^\s*0x([0-9a-fA-F]{1,2})\s+\'([^\']+)\'\s*$/) {
  2626.         my $uni = ord ($2);
  2627.         my $c = hex ($1);
  2628.         $acmtable{$uni} = $c;
  2629.     } else {
  2630.         die "$0: Syntax error in ACM file: $_\n";
  2631.     }
  2632.     }
  2633.     close ACM;
  2634. }
  2635.  
  2636. ########### PARSING ###############################################
  2637.  
  2638. # Report a syntax error in $filename. $_[0] should describe what was
  2639. # expected at $stream.
  2640. sub syntax_error {
  2641.     die "$0: instead of \"". (substr ($stream, 0, 50))
  2642.     ."\" in $filename expected $_[0].\n";
  2643. }
  2644.  
  2645. # Opens the text file $_[0], reads it and saves its contents in $stream
  2646. # The comments are removed, all new lines are replaced by spaces and
  2647. # all redundant spaces are removed.
  2648. sub file_to_string {
  2649.     my $file = $_[0];
  2650.     my $string = '';
  2651.     open (FILE, "$file") or die "$0: $file: $!\n";
  2652.     while (<FILE>) {
  2653.     chomp;
  2654.     s{//.*}{};
  2655.     s{\#.*}{};
  2656.     $string = $string . $_ .' ';
  2657.     }
  2658.     close FILE;
  2659.     
  2660.     my $normalized = '';
  2661.     my $final_letter = 0;
  2662.     while ($string) {
  2663.     if ($string =~ s/^\s+// && $final_letter && $string =~ /^[a-zA-Z0-9]/) {
  2664.         $normalized = $normalized .' ';
  2665.         $final_letter = 0;
  2666.     }
  2667.     if ($string =~ s/^([^\"\s]+)//) {
  2668.         $normalized = $normalized . $1;
  2669.         $final_letter = ($1 =~ /[a-zA-Z0-9]$/);
  2670.         next;
  2671.     }
  2672.     if ($string =~ s/^(\"[^\"]*(\"|$))//) {
  2673.         $normalized = $normalized . $1;
  2674.         $final_letter = 0;
  2675.         if ($2 ne '"') {
  2676.         die "$0: missing quote in ". (substr ($1, 0, 50)) ."...\n";
  2677.         }
  2678.         next;
  2679.     }
  2680.     (! $string ) or die "Internal error";
  2681.     }
  2682.     $stream = $normalized;
  2683. }
  2684.  
  2685. # removes from $stream initial sequence of xkb flags (default, partial,
  2686. # hidden, etc.) Returns true if the "default" flag was among them.
  2687. sub xkb_flags {
  2688.     my $default = 0;
  2689.     while ($stream =~ s/^(default|partial|hidden
  2690.               |alphanumeric_keys|modifier_keys
  2691.               |keypad_keys|function_keys
  2692.               |alternate_group)\s?(.*)/$2/ix) {
  2693.     $default = 1 if ($1 =~ /default/i);
  2694.     }
  2695.     return $default;
  2696. }
  2697.  
  2698. # Removes and returns identifier from $stream. 
  2699. sub xkb_identifier {
  2700.     if ($stream =~ s/^([a-zA-Z0-1_]+) ?(.*)/$2/) {
  2701.     return $1;
  2702.     } else {
  2703.     syntax_error "identifier";
  2704.     }
  2705. }
  2706.  
  2707. # Removes and returns a string from $stream.
  2708. sub xkb_string {
  2709.     if ($stream =~ /^\"([^\"]*)\"(.*)/) {
  2710.     $stream = $2;
  2711.     return $1;
  2712.     } else {
  2713.     syntax_error "string";
  2714.     }
  2715. }
  2716.  
  2717. # Removes an include method name from $stream and returns $alternate_method,
  2718. # $augment_method, $replace_method, or $override_method.  If $stream
  2719. # does not start with a method name, return the default method (i.e. $method)
  2720. sub xkb_method {
  2721.     if ($stream =~ s/^alternate ?(.*)/$1/i) {
  2722.     return $alternate_method;
  2723.     } elsif ($stream =~ s/^augment ?(.*)/$1/i) {
  2724.     return $augment_method;
  2725.     } elsif ($stream =~ s/^replace ?(.*)/$1/i) {
  2726.     return $replace_method;
  2727.     } elsif ($stream =~ s/^override ?(.*)/$1/i) {
  2728.     return $override_method;
  2729.     } else {
  2730.     return $method;
  2731.     }
  2732. }
  2733.  
  2734. # If $stream starts with an include statement - process it and return true.
  2735. # Otherwise return false. $_[0] is the file type ("symbols" or "keycodes")
  2736. sub xkb_include {
  2737.     my $file_type = $_[0];
  2738.     if ($stream =~ s/^(include|replace|augment|override)\"([^\"]*)\";?
  2739.                         (.*)/$3/ix) {
  2740.     my $method_name = $1;
  2741.     my $include_request = $2;
  2742.     if ($method != $ignore_method) {
  2743.         my $oldmethod = $method;
  2744.         if ($method_name =~ /replace/i) {
  2745.         $method = $replace_method;
  2746.         } elsif ($method_name =~ /augment/i) {
  2747.         $method = $augment_method;
  2748.         } elsif ($method_name =~ /override/i) {
  2749.         $method = $override_method;
  2750.         }
  2751.         &include_xkb_file ($file_type, $include_request);
  2752.         $method = $oldmethod;
  2753.     }
  2754.     return 1;
  2755.     } else {
  2756.     return 0;
  2757.     }
  2758. }
  2759.  
  2760. sub xkb_keycodes_definitions {
  2761.     my $oldmethod = $method;
  2762.     while ($stream) {
  2763.     $method = $oldmethod;
  2764.  
  2765.     if (xkb_include ('keycodes')) {
  2766.         next;
  2767.     }
  2768.  
  2769.     $method = xkb_method ();
  2770.     
  2771.     if ($stream =~ (s/^(minimum|maximum|indicator|virtual\sindicator)
  2772.             [^;]*;(.*)/$2/ix)) {
  2773.         next;
  2774.     }
  2775.  
  2776.     if ($stream =~ /^<([^>]*)>=/) {
  2777.         $stream =~ s/^<([^>]+)>=([0-9]*);(.*)/$3/
  2778.         or syntax_error "keycode definition";
  2779.         my $key = $1;
  2780.         my $code = $2;
  2781.         if ($method == $replace_method
  2782.         || $method == $override_method
  2783.         || ($method == $augment_method
  2784.             && ! defined $keycodes_table{$key})) {
  2785.         $keycodes_table{$key} = [ $code ];
  2786.         delete $aliases{$key};
  2787.         } elsif ($method == $alternate_method) {
  2788.         push @{$keycodes_table{$key}}, $code;
  2789.         }
  2790.         next;
  2791.     }
  2792.     if ($stream =~ /^alias/) {
  2793.         $stream =~ s/^alias<([^>]+)>=<([^>]+)>;(.*)/$3/
  2794.         or syntax_error "alias definition";
  2795.         my $alias = $1;
  2796.         my $key = $2;
  2797.         if ($method == $replace_method
  2798.         || $method == $override_method
  2799.         || ($method == $augment_method
  2800.             && ! defined $keycodes_table{$alias})) {
  2801.         $keycodes_table{$alias} = [];
  2802.         $aliases{$alias} = $key;
  2803.         }
  2804.         next;
  2805.     }
  2806.     last;
  2807.     }
  2808.     $method = $oldmethod;
  2809. }
  2810.  
  2811. # Fill @{$symbols_table{$code}[$group]} with symbols
  2812. sub symbols_for_group {
  2813.     my $code = shift;
  2814.     my $group = shift;
  2815.     if ($method == $replace_method
  2816.     || ($method == $override_method
  2817.         && (@_ || ! defined $symbols_table{$code}[$group]))
  2818.     || ($method == $augment_method &&
  2819.         ! defined $symbols_table{$code})) {
  2820.     my $level = 0;
  2821.     for my $symbol (@_) {
  2822.         if ($symbol !~ /\(/ && $symbol =~ /./
  2823.         && (! defined $xkbsym_table{$symbol}
  2824.             || $xkbsym_table{$symbol} ne 'NoSymbol'
  2825.             || ! defined $symbols_table{$code}[$group][$level])) {
  2826.         $symbols_table{$code}[$group][$level] = $symbol;
  2827.         }
  2828.         $level++;
  2829.     }
  2830.     }
  2831. }
  2832.  
  2833. # KPDL needs a special tweak for certain layouts.
  2834. sub adjust_symbols {
  2835.     my $key = shift;
  2836.     if ($key eq 'KPDL') {
  2837.     my @newsymbols;
  2838.     for my $symbol (@_) {
  2839.         if ($symbol eq 'period') {
  2840.         push @newsymbols, 'KP_Decimal';
  2841.         } elsif ($symbol eq 'comma') {
  2842.         push @newsymbols, 'KP_Separator';
  2843.         } else {
  2844.         push @newsymbols, $symbol;
  2845.         }
  2846.     }
  2847.     return @newsymbols;
  2848.     } else {
  2849.     return @_;
  2850.     }
  2851. }
  2852.  
  2853. sub xkb_key {
  2854.     my $default_key_type = $_[0];
  2855.     if ($stream =~ /^key</i) {
  2856.     $stream =~ s/^key<([^>]+)>\{([^\}]*?)\};(.*)/$3/i
  2857.         or syntax_error "key definition";
  2858.     my $key = $1;
  2859.     my $list = $2 .",";
  2860.     if ($verbosity >= 4 && ! defined $keycodes_table{$key}) {
  2861.         warning "No scan code for <$key> is defined.\n";
  2862.     }
  2863.     for my $code (@{$keycodes_table{$key}}) {
  2864.         if ($method == $replace_method) {
  2865.         $symbols_table{$code} = [];
  2866.         }
  2867.         my $group = $base_group;
  2868.         while ($list =~ /[^ ]/) {
  2869.         # [ X1, X2, ... ]
  2870.         if ($list =~ s/^\[([^\]]*?)\],(.*)/$2/) {
  2871.             (my $symbols = $1) =~ s/,/ /g;
  2872.             my @groupsymbols = split ' ', $symbols;
  2873.             @groupsymbols = adjust_symbols $key, @groupsymbols;
  2874.             symbols_for_group $code, $group, @groupsymbols;
  2875.             $group++;
  2876.             next;
  2877.         }
  2878.         # symbols[GroupN] = [ X1, X2, ... ]
  2879.         if ($list =~ (s/^symbols\[Group([1-4])\]
  2880.                   =\[([^\]]*?)\],(.*)/$3/x)) {
  2881.             my $group = $1 - 1 + $base_group;
  2882.             (my $symbols = $2) =~ s/,/ /g;
  2883.             my @groupsymbols = split ' ', $symbols;
  2884.             @groupsymbols = adjust_symbols $key, @groupsymbols;
  2885.             symbols_for_group $code, $group, @groupsymbols;
  2886.             next;
  2887.         }
  2888.         # type = "...."
  2889.         if ($list =~ (s/^type(?:\[Group1\])?
  2890.                               =\"([^\"]+)\",(.*)/$2/x)) {
  2891.             if ($method == $replace_method
  2892.             || $method == $override_method
  2893.             || ($method == $augment_method
  2894.                 && ! defined $types_table{$code})) {
  2895.             $types_table{$code} = $1;
  2896.             }
  2897.             next;
  2898.         }
  2899.         # abracadabra
  2900.         # abracadabra = abra<cad>abra
  2901.         next if ($list =~ s/^[a-zA-Z0-9_]+(=[a-zA-Z0-9_<>]+)?,
  2902.                                    (.*)/$2/x);
  2903.         # abracadabra = "...."
  2904.         next if ($list =~ s/^[a-zA-Z0-9_]+=\"[^\"]+\",(.*)/$1/);
  2905.         # type[...] = "..."
  2906.         next if ($list =~ s/^type\[[a-zA-Z0-9_]+\]=\"[^\"]+\",
  2907.                                     (.*)/$1/x);
  2908.         die "$0: garbage in a key definition: \"$list\""
  2909.             ." in $filename.\n";
  2910.         }
  2911.         if (! defined $types_table{$code}
  2912.         || $types_table{$code} eq 'DEFAULT') {
  2913.         $types_table{$code} = $default_key_type;
  2914.         }
  2915.     }
  2916.     return 1;
  2917.     } else {
  2918.     return 0;
  2919.     }
  2920. }
  2921.  
  2922. sub xkb_symbols_definitions {
  2923.     my $oldmethod = $method;
  2924.     my $default_key_type = 'DEFAULT';
  2925.     while ($stream) {
  2926.     $method = $oldmethod;
  2927.  
  2928.     if (xkb_include ('symbols')) {
  2929.         next;
  2930.     }
  2931.  
  2932.     $method = xkb_method ();
  2933.  
  2934.     if ($stream =~ /^name/i) {
  2935.         $stream =~ s/^name\[[a-zA-Z0-9]+\]=\"[^\"]*\";(.*)/$1/i
  2936.         or syntax_error "group name";
  2937.         next;
  2938.     }
  2939.  
  2940.     if ($stream =~ (s/^key\.type(?:\[Group1\])?=\"([^\"]+)\";(.*)/$2/)) {
  2941.         $default_key_type = $1;
  2942.         next;
  2943.     }
  2944.     
  2945.     if ($stream =~ s/^[a-zA-Z0-9]+\.[a-zA-Z0-9]+=.*?;(.*)/$1/i) {
  2946.         next;
  2947.     }
  2948.  
  2949.     if ($stream =~ s/^[a-zA-Z0-9]+\.[a-zA-Z0-9]+\[[a-zA-Z0-9]+\]
  2950.                        =.*?;(.*)/$1/ix) {
  2951.         next;
  2952.     }
  2953.  
  2954.     if (xkb_key $default_key_type) {
  2955.         next;
  2956.     }
  2957.  
  2958.     if ($stream =~ /^(modifier_map|modmap|mod_map)/i) {
  2959.         $stream =~ (s/^(modifier_map|modmap|mod_map)\s?[a-zA-Z0-9_]+
  2960.             \{[^\}]*\};(.*)/$2/ix)
  2961.         or syntax_error "modifier_map";
  2962.         next;
  2963.     }
  2964.  
  2965.     if ($stream =~ /^virtual_modifiers/i) {
  2966.         $stream =~ (s/^virtual_modifiers\s?[a-zA-Z0-9_,]+;(.*)/$1/ix)
  2967.         or syntax_error "virtual_modifiers";
  2968.         next;
  2969.     }
  2970.     last;
  2971.     }
  2972.     $method = $oldmethod;
  2973. }
  2974.  
  2975. sub xkb_definitions {
  2976.     my $file_type = $_[0];
  2977.     if ($file_type eq 'symbols') {
  2978.     xkb_symbols_definitions();
  2979.     } elsif ($file_type eq 'keycodes') {
  2980.     xkb_keycodes_definitions();
  2981.     } else {
  2982.     die "$0: Bad xkb file type $file_type\n";
  2983.     }
  2984. }
  2985.  
  2986. # Remove from $stream the characters up to the first unmatched "}"
  2987. sub skip_to_brace {
  2988.     while ($stream && ($stream =~ s/^[^\}\{]*\{//)) {
  2989.     &skip_to_brace;
  2990.     }
  2991.     $stream =~ s/^[^\}\{]*(\}|$)//;
  2992. }
  2993.  
  2994. sub xkb_block_list {
  2995.     my $file_type = $_[0];
  2996.     my $block = $_[1];
  2997.     my $first = 1;
  2998.     my $ok = 0;
  2999.     my $mystream = $stream;
  3000.     while ($stream) {
  3001.     my $default = xkb_flags();
  3002.     xkb_identifier() eq "xkb_". $file_type
  3003.         or syntax_error "xkb_". $file_type;
  3004.     my $name = xkb_string();
  3005.     my $structured;
  3006.     if ($stream =~ s/^\{//) {
  3007.         $structured = 1;
  3008.     } else {
  3009.         $structured = 0;
  3010.     }
  3011.     if ($name eq $block || ($first && ! $block)) {
  3012.         xkb_definitions ($file_type);
  3013.         if ($structured) {
  3014.         $stream =~ s/^\};.*// or syntax_error "};";
  3015.         } else {
  3016.         $stream = '';
  3017.         }
  3018.         $ok = 1;
  3019.     } else {
  3020.         if ($structured) {
  3021.         skip_to_brace;
  3022.         $stream =~ s/^;// or syntax_error ";";
  3023.         } else {
  3024.         last;
  3025.         }
  3026.     }
  3027.     $first = 0;
  3028.     }
  3029.     if (! $ok) {
  3030.     $stream = $mystream;
  3031.     }
  3032.     return $ok;
  3033. }
  3034.  
  3035. sub include_xkb_file {
  3036.     my $file_type = $_[0];
  3037.     my $include_list = '^'. $_[1];
  3038.  
  3039.     my $oldmethod = $method;
  3040.     my $oldbase_group = $base_group;
  3041.     while ($include_list) {
  3042.     my $file;
  3043.     my $block;
  3044.     if ($include_list =~ (s/^(\^|\+|\|)([^\(\|\+]+)\(([^\)]+)\)
  3045.                   :([1234])(.*)/$5/x)) {
  3046.         if ($1 eq '+') {
  3047.         $method = $override_method;
  3048.         } elsif ($1 eq '|') {
  3049.         $method = $augment_method;
  3050.         }
  3051.         $file = $2;
  3052.         $block = $3;
  3053.         $base_group = $4 - 1 + $base_group;
  3054.     } elsif ($include_list =~ (s/^(\^|\+|\|)([^\(\|\+]+)\(([^\)]+)\)
  3055.                    (.*)/$4/x)) {
  3056.         if ($1 eq '+') {
  3057.         $method = $override_method;
  3058.         } elsif ($1 eq '|') {
  3059.         $method = $augment_method;
  3060.         }
  3061.         $file = $2;
  3062.         $block = $3;
  3063.     } elsif ($include_list =~ s/^(\^|\+|\|)([^\(\|\+]+):([1234])(.*)/$4/) {
  3064.         if ($1 eq '+') {
  3065.         $method = $override_method;
  3066.         } elsif ($1 eq '|') {
  3067.         $method = $augment_method;
  3068.         }
  3069.         $file = $2;
  3070.         $block = '';
  3071.         $base_group = $3 - 1 + $base_group;
  3072.     } elsif ($include_list =~ s/^(\^|\+|\|)([^\(\|\+]+)(.*)/$3/) {
  3073.         if ($1 eq '+') {
  3074.         $method = $override_method;
  3075.         } elsif ($1 eq '|') {
  3076.         $method = $augment_method;
  3077.         }
  3078.         $file = $2;
  3079.         $block = '';
  3080.     } else {
  3081.         die "$0: bad include list $include_list.\n";
  3082.     }
  3083.     
  3084.     my $oldstream = $stream;
  3085.     if ($file =~ /^\.?\//) {
  3086.         $stream = file_to_string ("$file");
  3087.     } else {
  3088.         $stream = file_to_string (xfilename "$file_type/$file");
  3089.     }
  3090.     my $oldfilename = $filename;
  3091.     $filename = $file;
  3092.     if (!xkb_block_list ($file_type, $block)) {
  3093.         warning "Can not find \"$block\" in \"$file\".\n";
  3094.         xkb_block_list ($file_type, '');
  3095.     }
  3096.     $stream = $oldstream;
  3097.     $filename = $oldfilename;
  3098.     $method = $oldmethod;
  3099.     $base_group = $oldbase_group;
  3100.     }
  3101. }
  3102.  
  3103. include_xkb_file 'keycodes', $keycodes;
  3104.  
  3105. foreach my $alias (keys %aliases) {
  3106.     if (! defined $keycodes_table{$aliases{$alias}}) {
  3107.     die "$0: undefined keyname $aliases{$alias} in ".
  3108.         "an keycode alias definition in $filename.\n";
  3109.     }
  3110.     $keycodes_table{$alias} = [ @{$keycodes_table{$alias}},
  3111.                 @{$keycodes_table{$aliases{$alias}}} ];
  3112. }
  3113.  
  3114. include_xkb_file 'symbols', $symbols;
  3115.  
  3116. foreach my $key (keys %symbols_table) {
  3117.     foreach my $group (0 .. $#{$symbols_table{$key}}) {
  3118.     if (! defined $symbols_table{$key}[$group]) {
  3119.         $symbols_table{$key}[$group] = [];
  3120.     } else {
  3121.         foreach my $level (0 .. $#{$symbols_table{$key}[$group]}) {
  3122.         if (! defined $symbols_table{$key}[$group][$level]) {
  3123.             $symbols_table{$key}[$group][$level] = 'NoSymbol';
  3124.         }
  3125.         }
  3126.     }
  3127.     }
  3128.     if (! defined $types_table{$key}) {
  3129.     $types_table{$key} = 'DEFAULT';
  3130.     }
  3131. }
  3132.  
  3133. # later we use that the distance is an even number less than 1000000
  3134. sub distance {
  3135.     my $x = $_[0];
  3136.     my $y = $_[1];
  3137.     my $bottom = $x & $y;
  3138.     # If groups differ prefer the zero group
  3139.     if (($x | 0x0f) != ($y | 0x0f)) {
  3140.     $bottom = $bottom & 0x0f;
  3141.     }
  3142.     return  ((($y - $bottom) << 6) | ($x - $bottom)) << 1;
  3143. }
  3144.  
  3145. sub uni_to_legacy {
  3146.     my $uni = $_[0];
  3147.     if ($acm) {
  3148.     if ($uni <= 0x7f) {
  3149.         return sprintf "0x%02x", $uni;
  3150.     } elsif (defined $acmtable{$uni}) {
  3151.         return sprintf "0x%02x", $acmtable{$uni};
  3152.     } else {
  3153.         if ($verbosity >= 8) {
  3154.         warning sprintf ("Unicode U+%04x does not exist "
  3155.                  ."in the legacy encoding\n", $uni);
  3156.         }
  3157.         return 'VoidSymbol';
  3158.     }
  3159.     } else {
  3160.     return 'U+'. sprintf ("%04x", $uni);
  3161.     }
  3162. }
  3163.  
  3164. sub x_to_kernelsym {
  3165.     my $xkeysym = $_[0];
  3166.     my $kernelkeysym = $xkbsym_table{$xkeysym};
  3167.     if (defined $kernelkeysym) {
  3168.         if ($kernelkeysym !~ /^[0-9a-fA-F]{4}$/) {
  3169.         return $kernelkeysym;
  3170.     }
  3171.     } else {
  3172.     $kernelkeysym = ($xkeysym =~ /^0x0?100([0-9a-fA-F]{4})$/
  3173.              ? $1
  3174.              : ($xkeysym =~ /^U([0-9a-fA-F]+)$/
  3175.                 ? $1 
  3176.                 : undef));
  3177.     }
  3178.     if (defined $kernelkeysym) {
  3179.     my $uni = hex ($kernelkeysym);
  3180.     if (defined $forbidden{$uni}) {
  3181. #        warning "Forbidden Unicode \"U+$kernelkeysym\"\n";
  3182.         return 'VoidSymbol';
  3183.     } else {
  3184.         if (pack("U", $uni) =~ /\p{IsAlpha}/) {
  3185.         my $legacy = uni_to_legacy ($uni);
  3186.         if ($legacy ne 'VoidSymbol') {
  3187.             return '+'. $legacy;
  3188.         } else {
  3189.             return $legacy;
  3190.         }
  3191.         } elsif ($uni <= 0x1f) {
  3192.         return $controlsyms[$uni + 1];
  3193.         } else {
  3194.         return uni_to_legacy ($uni);
  3195.         }
  3196.     }
  3197.     } else {
  3198.     warning "Unknown X keysym \"$xkeysym\"\n";
  3199.     return 'VoidSymbol';
  3200.     }
  3201. }
  3202.  
  3203. sub x_to_ascii {
  3204.     my $xkeysym = $_[0];
  3205.     my $kernelkeysym = $xkbsym_table{$xkeysym};
  3206.     if (defined $kernelkeysym) {
  3207.     if ($kernelkeysym eq 'Delete') {
  3208.         return 0x7f;
  3209.     } elsif ($kernelkeysym eq 'BackSpace') {
  3210.         return 0x08;
  3211.     } elsif ($kernelkeysym eq 'Tab') {
  3212.         return 0x09;
  3213.     } elsif ($kernelkeysym eq 'Linefeed') {
  3214.         return 0x0a;
  3215.     } elsif ($kernelkeysym eq 'Return') {
  3216.         return 0x0d;
  3217.     } elsif ($kernelkeysym eq 'Escape') {
  3218.         return 0x1b;
  3219.     } elsif ($kernelkeysym eq 'NoSymbol') {
  3220.         return -1;
  3221.     } elsif ($kernelkeysym !~ /^[0-9a-fA-F]{4}$/) {
  3222.         return undef;
  3223.     }
  3224.     } else {
  3225.     $kernelkeysym = ($xkeysym =~ /^0x0?100([0-9a-fA-F]{4})/
  3226.              ? $1
  3227.              : ($xkeysym =~ /^U([0-9a-fA-F]+)/
  3228.                 ? $1 
  3229.                 : undef));
  3230.     }
  3231.     if (defined $kernelkeysym) {
  3232.     my $uni = hex ($kernelkeysym);
  3233.     if (0x00 <= $uni && 0x7f >= $uni) {
  3234.         return $uni;
  3235.     }
  3236.     }
  3237.     return undef;
  3238. }
  3239.  
  3240. # A vector of symbol codes for a key
  3241. my @vector;
  3242. # A vector with same length as @vector.  Measures how well each element of
  3243. # @vector represents the xkb symbol for the particular key.  Bigger values
  3244. # mean lower quality.
  3245. my @quality;
  3246.  
  3247. sub approximate {
  3248.     my ($coord, $new_sym, $new_quality) = @_;
  3249.     # $new_sym represents the xkb symbol for position $coord in @vector
  3250.     # with quality $new_quality
  3251.     if ((! defined $quality[$coord] 
  3252.      || $quality[$coord] > $new_quality)
  3253.     && $new_sym ne 'VoidSymbol') {
  3254.     $vector[$coord] = $new_sym;
  3255.     $quality[$coord] = $new_quality;
  3256.     }
  3257. }
  3258.  
  3259. # Fill @vector with data for key number $_[0]
  3260. sub flatten {
  3261.     #    Kernel         X
  3262.     # -----------------------------------------
  3263.     # 1  Shift          level 2 (Shift)
  3264.     # 2  AltGr          levels 3 and 4 (AltGr)
  3265.     # 4  Control        Control
  3266.     # 8  Alt            Alt
  3267.     # 0                 Group1
  3268.     # 16 ShiftL         Group2
  3269.     # 32 ShiftR         Group4
  3270.     # 48 ShiftL+ShiftR  Group3
  3271.     my $key = $_[0];
  3272.     @vector = ();
  3273.     @quality = ();
  3274.     for my $group (0..3) {
  3275.     my $real_group = $group;
  3276.     if ($real_group == 3) {
  3277.         $real_group = 2;
  3278.     } elsif ($real_group == 2) {
  3279.         $real_group = 3;
  3280.     }
  3281.     while ($real_group > $#{$symbols_table{$key}}) {
  3282.         if ($real_group >= 2) {
  3283.         $real_group = $real_group - 2;
  3284.         } else {
  3285.         $real_group = $real_group - 1;
  3286.         }
  3287.     }
  3288.     next if ($real_group < 0);
  3289.     for my $level (0..3) {
  3290.         my $real_level = $level;
  3291.         while ($real_level > $#{$symbols_table{$key}[$real_group]}) {
  3292.         if ($real_level == 2) {
  3293.             $real_level = $real_level - 2;
  3294.         } else {
  3295.             $real_level = $real_level - 1;
  3296.         }
  3297.         }
  3298.         next if ($real_level < 0);
  3299.         my $coord;
  3300.         for ($types_table{$key}) {
  3301.         if (/^(DEFAULT|ONE_LEVEL|TWO_LEVEL
  3302.                       |THREE_LEVEL|ALPHABETIC
  3303.                       |EIGHT_LEVEL|EIGHT_LEVEL_ALPHABETIC
  3304.                       |FOUR_LEVEL|FOUR_LEVEL_ALPHABETIC
  3305.                       |FOUR_LEVEL_SEMIALPHABETIC
  3306.                       |SEPARATE_CAPS_AND_SHIFT_ALPHABETIC
  3307.               |KEYPAD|FOUR_LEVEL_X|FOUR_LEVEL_MIXED_KEYPAD
  3308.               |FOUR_LEVEL_KEYPAD|LOCAL_EIGHT_LEVEL
  3309.                       |FOUR_LEVEL_PLUS_LOCK
  3310.                       )$/x) {
  3311.             # Level1: plain
  3312.             # Level2: shift
  3313.             # Level3: altgr
  3314.             # Level4: shift+altgr
  3315.             $coord = ($group << 4) + $level;
  3316.         } elsif (/^(PC_BREAK|PC_CONTROL_LEVEL2
  3317.                            |PC_LCONTROL_LEVEL2|PC_RCONTROL_LEVEL2)$/x) {
  3318.             # Level1: plain
  3319.             # Level2: control
  3320.             if ($level == 0 || $level == 2) {
  3321.             $coord = ($group << 4) + $level;
  3322.             } else {
  3323.             $coord = ($group << 4) + $level + 3;
  3324.             }
  3325.         } elsif (/^(PC_SYSRQ|PC_ALT_LEVEL2
  3326.                            |PC_LALT_LEVEL2|PC_RALT_LEVEL2)$/x) {
  3327.             # Level1: plain
  3328.             # Level2: alt
  3329.             if ($level == 0 || $level == 2) {
  3330.             $coord = ($group << 4) + $level;
  3331.             } else {
  3332.             # notice that $level is 1 or 3
  3333.             $coord = ($group << 4) + $level + 7;
  3334.             }
  3335.         } elsif (/^SHIFT\+ALT$/) {
  3336.             # Level1: plain
  3337.             # Level2: shift+alt
  3338.             if ($level == 0 || $level == 2) {
  3339.             $coord = ($group << 4) + $level;
  3340.             } else {
  3341.             $coord = ($group << 4) + $level + 8;
  3342.             }
  3343.         } elsif (/^CTRL\+ALT$/) {
  3344.             # Level1: plain
  3345.             # Level2: control+alt
  3346.             if ($level == 0 || $level == 2) {
  3347.             $coord = ($group << 4) + $level;
  3348.             } else {
  3349.             $coord = ($group << 4) + $level + 11;
  3350.             }
  3351.         } else {
  3352.             warning "Unknown key type $types_table{$key}\n";
  3353.             $coord = ($group << 4) + $level;
  3354.         }
  3355.         }
  3356.         my $xkeysym = $symbols_table{$key}[$real_group][$real_level];
  3357.         my $is_special = ($xkeysym !~ /^U[0-9a-fA-F]+$/
  3358.                   && defined $xkbsym_table{$xkeysym}
  3359.                   && ($xkbsym_table{$xkeysym}
  3360.                   !~ /^[0-9a-fA-F]{4}$/));
  3361.         my $kernelkeysym = x_to_kernelsym ($xkeysym);
  3362.         my $ascii = x_to_ascii ($xkeysym);
  3363.         approximate ($coord, $kernelkeysym, 0);
  3364.         for my $approximated_group (0 .. 3) {
  3365.         for my $approximated_level (0 .. 3) {
  3366.             my $approximated_coord = ($approximated_level
  3367.                           + ($approximated_group << 4));
  3368.             my $distance = distance ($approximated_coord, $coord);
  3369.             approximate ($approximated_coord,
  3370.                  $kernelkeysym, $distance);
  3371.             if (defined $ascii) {
  3372.             approximate (($approximated_coord | 0x08), 
  3373.                      $metasyms[$ascii + 1], $distance + 1);
  3374.             approximate (($approximated_coord | 0x04), 
  3375.                      $controlsyms[$ascii + 1], $distance + 1);
  3376.             approximate (($approximated_coord | 0x0c), 
  3377.                      $metacontrolsyms[$ascii + 1], 
  3378.                      $distance + 1);
  3379.             } elsif ($is_special) {
  3380.             approximate (($approximated_coord | 0x08), 
  3381.                      $kernelkeysym, $distance + 1);
  3382.             approximate (($approximated_coord | 0x04), 
  3383.                      $kernelkeysym, $distance + 1);
  3384.             approximate (($approximated_coord | 0x0c), 
  3385.                      $kernelkeysym, $distance + 1);
  3386.             }
  3387.         }
  3388.         }
  3389.     }
  3390.     }
  3391.     for my $coord (0 .. 63) {
  3392.     if (! defined $vector[$coord]) {
  3393.         $vector[$coord] = 'VoidSymbol';
  3394.     }
  3395.     }
  3396.  
  3397.     for my $coord (0 .. 63) {
  3398.     next if ($coord & 0x0c); # If Control and/or Alt
  3399.     my $mask = $kernel_modifiers{$vector[$coord]};
  3400.     next unless (defined $mask);
  3401.     for my $mod (4, 8, 12) {
  3402.         if ($vector[$coord + $mod] eq 'VoidSymbol'
  3403.         && ($vector[($coord + $mod) ^ $mask] eq 'VoidSymbol')) {
  3404.         $vector[$coord + $mod] = $vector[$coord];
  3405.         }
  3406.     }
  3407.     }
  3408.     
  3409.     # Without this it would be possible to lock permanently
  3410.     # a modifier key such as Control or Alt
  3411.     for my $coord (0 .. 63) {
  3412.     my $mask = $kernel_modifiers{$vector[$coord]};
  3413.     if (defined $mask) {
  3414.         $vector[$coord ^ $mask] = $vector[$coord];
  3415.         if ($compact) {
  3416.         # AltGr = 0x02,  ShiftL = 0x10
  3417.         if (($mask & 0x02) && ($mask & 0x10)) {
  3418.             $vector[$coord ^ $mask ^ 0x02] = $vector[$coord];
  3419.             $vector[$coord ^ $mask ^ 0x10] = $vector[$coord];
  3420.         } elsif ($mask & 0x02) {
  3421.             $vector[$coord ^ $mask ^ 0x10] = $vector[$coord];
  3422.             $vector[$coord ^ $mask ^ 0x10 ^ 0x02] = $vector[$coord];
  3423.         } elsif ($mask & 0x10) {
  3424.             $vector[$coord ^ $mask ^ 0x02] = $vector[$coord];
  3425.             $vector[$coord ^ $mask ^ 0x02 ^ 0x10] = $vector[$coord];
  3426.         }
  3427.         }
  3428.     }
  3429.     }
  3430.     
  3431.     if (! $compact) {
  3432.     for my $coord (16 .. 63) {
  3433.         if ($vector[$coord] =~ /^(ShiftL|ShiftL_Lock)$/) {
  3434.         $vector[$coord] = 'VoidSymbol';
  3435.         }
  3436.     }
  3437.     for my $coord (0 .. 15) {
  3438.         if ($vector[$coord] eq 'ShiftL_Lock') {   #  0 => 16
  3439.         $vector[$coord + 16] = 'ShiftR_Lock'; # 16 => 48
  3440.         $vector[$coord + 32] = 'ShiftR_Lock'; # 32 => 0
  3441.         $vector[$coord + 48] = 'ShiftL_Lock'; # 48 => 32
  3442.         } elsif ($vector[$coord] eq 'ShiftL') {
  3443.         $vector[$coord + 16] = 'ShiftL';
  3444.         $vector[$coord + 32] = 'ShiftL';
  3445.         $vector[$coord + 48] = 'ShiftL';
  3446.         }
  3447.     }
  3448.     } else {
  3449.     for my $coord (16 .. 63) {
  3450.         if ($vector[$coord] =~ /^(AltGr|AltGr_Lock)$/) {
  3451.         $vector[$coord] = 'VoidSymbol';
  3452.         }
  3453.     }
  3454.     for my $coord (0 .. 15) {
  3455.         if ($vector[$coord] eq 'AltGr_Lock') {
  3456.         $vector[$coord + 16] = 'AltGr_Lock';
  3457.         $vector[$coord + 32] = 'AltGr_Lock';
  3458.         $vector[$coord + 48] = 'AltGr_Lock';
  3459.         } elsif ($vector[$coord] eq 'AltGr') {
  3460.         $vector[$coord + 16] = 'AltGr';
  3461.         $vector[$coord + 32] = 'AltGr';
  3462.         $vector[$coord + 48] = 'AltGr';
  3463.         }
  3464.     }
  3465.     }
  3466.  
  3467.     for my $group (0 .. 3) {
  3468.     my $kp = undef;
  3469.     for my $x (0 .. 15) {
  3470.         my $coord = 16 * $group + $x;
  3471.         if ($vector[$coord] =~ /^KP_/) {
  3472.         $kp = $vector[$coord];
  3473.         last;
  3474.         }
  3475.     }
  3476.     if ($types_table{$key} =~ /^(KEYPAD|FOUR_LEVEL_X
  3477.                                     |FOUR_LEVEL_MIXED_KEYPAD
  3478.                             |FOUR_LEVEL_KEYPAD)$/x
  3479.         && ! defined $kp) {
  3480.         $kp = 'VoidSymbol';
  3481.     }
  3482.     if ($kp) {
  3483.         for my $x (0 .. 15) {
  3484.         my $coord = 16 * $group + $x;
  3485.         for ($vector[$coord]) {
  3486.             if (/^VoidSymbol$/) {
  3487.             # KP_Begin and KP_Delete are mapped to VoidSymbol
  3488.             $vector[$coord] = $kp;
  3489.             } elsif (/$xkbsym_table{'plus'}/) {# not anchored match!
  3490.             $vector[$coord] = 'KP_Add';
  3491.             } elsif (/$xkbsym_table{'minus'}/) {
  3492.             $vector[$coord] = 'KP_Subtract';
  3493.             } elsif (/$xkbsym_table{'asterisk'}/) {
  3494.             $vector[$coord] = 'KP_Multiply';
  3495.             } elsif (/$xkbsym_table{'slash'}/) {
  3496.             $vector[$coord] = 'KP_Divide';
  3497.             } elsif (/$xkbsym_table{'comma'}/) {
  3498.             $vector[$coord] = 'KP_Comma';
  3499.             } elsif (/$xkbsym_table{'period'}/) {
  3500.             $vector[$coord] = 'KP_Period';
  3501.             } elsif (/$xkbsym_table{'0'}/) {
  3502.             $vector[$coord] = 'KP_0';
  3503.             } elsif (/$xkbsym_table{'1'}/) {
  3504.             $vector[$coord] = 'KP_1';
  3505.             } elsif (/$xkbsym_table{'2'}/) {
  3506.             $vector[$coord] = 'KP_2';
  3507.             } elsif (/$xkbsym_table{'3'}/) {
  3508.             $vector[$coord] = 'KP_3';
  3509.             } elsif (/$xkbsym_table{'4'}/) {
  3510.             $vector[$coord] = 'KP_4';
  3511.             } elsif (/$xkbsym_table{'5'}/) {
  3512.             $vector[$coord] = 'KP_5';
  3513.             } elsif (/$xkbsym_table{'6'}/) {
  3514.             $vector[$coord] = 'KP_6';
  3515.             } elsif (/$xkbsym_table{'7'}/) {
  3516.             $vector[$coord] = 'KP_7';
  3517.             } elsif (/$xkbsym_table{'8'}/) {
  3518.             $vector[$coord] = 'KP_8';
  3519.             } elsif (/$xkbsym_table{'9'}/) {
  3520.             $vector[$coord] = 'KP_9';
  3521.             } elsif (/^(Return|Enter)$/) {
  3522.             $vector[$coord] = 'KP_Enter';
  3523.             } elsif (/^Home$/) {
  3524.             $vector[$coord] = 'KP_7';
  3525.             } elsif (/^Left$/) {
  3526.             $vector[$coord] = 'KP_4';
  3527.             } elsif (/^Up$/) {
  3528.             $vector[$coord] = 'KP_8';
  3529.             } elsif (/^Right$/) {
  3530.             $vector[$coord] = 'KP_6';
  3531.             } elsif (/^Down$/) {
  3532.             $vector[$coord] = 'KP_2';
  3533.             } elsif (/^Prior$/) {
  3534.             $vector[$coord] = 'KP_9';
  3535.             } elsif (/^Next$/) {
  3536.             $vector[$coord] = 'KP_3';
  3537.             } elsif (/^End$/) {
  3538.             $vector[$coord] = 'KP_1';
  3539.             } elsif (/^Insert$/) {
  3540.             $vector[$coord] = 'KP_0';
  3541.             }
  3542.         }
  3543.         }
  3544.     }
  3545.     }
  3546.  
  3547.     for my $group (0 .. 3) {
  3548.     my $coord = $group << 4;
  3549.     my $mainsym = $vector[$coord];
  3550.     if ($mainsym =~ /^F([0-9]+)$/) {
  3551.         my $num = $1;
  3552.         $vector[$coord + 1] = 'F'. ($num + 12); # shift
  3553.         $vector[$coord + 2] = 'Console_'. ($num + 12); # altgr
  3554.         $vector[$coord + 3] = 'Console_'. ($num + 24); # altgr + shift
  3555.         $vector[$coord + 4] = 'F'. ($num + 24); # control
  3556.         $vector[$coord + 5] = 'F'. ($num + 36); # control + shift
  3557.         $vector[$coord + 6] = 'Console_'. ($num + 12); # control + altgr
  3558.         $vector[$coord + 7] = 'Console_'. ($num + 24); # control+altgr+shift
  3559.         $vector[$coord + 8] = 'Console_'. $num; # alt
  3560.         $vector[$coord + 9] = 'Console_'. ($num + 12); # alt + shift
  3561.         $vector[$coord + 12] = 'Console_'. $num; # control + alt
  3562.         $vector[$coord + 13] = 'Console_'. ($num + 12); # control+alt+shift
  3563.     } elsif ($mainsym eq 'Scroll_Lock' || $mainsym eq 'Help') {
  3564.         $vector[$coord + 1] = 'Show_Memory';
  3565.         $vector[$coord + 2] = 'Show_Registers';
  3566.         $vector[$coord + 4] = 'Show_State';
  3567.         $vector[$coord + 8] = 'Show_Registers';
  3568.     } elsif ($mainsym =~ /^KP_([0-9])$/) {
  3569.         my $num = $1;
  3570.         $vector[$coord + 2] = 'Hex_'. $num;
  3571.         $vector[$coord + 9] = 'Hex_'. $num;
  3572.         $vector[$coord + 8] = 'Ascii_'. $num;
  3573.     } elsif ($mainsym eq 'Num_Lock') {
  3574.         $vector[$coord + 2] = 'Hex_A';
  3575.         $vector[$coord + 9] = 'Hex_A';
  3576.     } elsif ($mainsym eq 'KP_Divide') {
  3577.         $vector[$coord + 2] = 'Hex_B';
  3578.         $vector[$coord + 9] = 'Hex_B';
  3579.     } elsif ($mainsym eq 'KP_Multiply') {
  3580.         $vector[$coord + 2] = 'Hex_C';
  3581.         $vector[$coord + 9] = 'Hex_C';
  3582.     } elsif ($mainsym eq 'KP_Subtract') {
  3583.         $vector[$coord + 2] = 'Hex_D';
  3584.         $vector[$coord + 9] = 'Hex_D';
  3585.     } elsif ($mainsym eq 'KP_Add') {
  3586.         $vector[$coord + 2] = 'Hex_E';
  3587.         $vector[$coord + 9] = 'Hex_E';
  3588.     } elsif ($mainsym eq 'KP_Enter') {
  3589.         $vector[$coord + 2] = 'Hex_F';
  3590.         $vector[$coord + 9] = 'Hex_F';
  3591.     } elsif ($mainsym eq 'Prior' || $mainsym eq 'PageUp') {
  3592.         $vector[$coord + 1] = 'Scroll_Backward';
  3593.     } elsif ($mainsym eq 'Next' || $mainsym eq 'PageDown') {
  3594.         $vector[$coord + 1] = 'Scroll_Forward';
  3595.     } elsif ($mainsym eq 'Left') {
  3596.         $vector[$coord + 8] = 'Decr_Console';
  3597.     } elsif ($mainsym eq 'Right') {
  3598.         $vector[$coord + 8] = 'Incr_Console';
  3599.     } elsif ($mainsym eq 'Up') {
  3600.         $vector[$coord + 8] = 'KeyboardSignal';
  3601.     }
  3602.     }
  3603.     return @vector;
  3604. }
  3605.  
  3606. sub print_vector {
  3607.     my $kernel_code = $_[0];
  3608.     my $no_NoSymbol = 1;
  3609.     for my $mask (0 .. 63) {
  3610.     if ($vector[$mask] eq 'NoSymbol') {
  3611.         $no_NoSymbol = 0;
  3612.         last;
  3613.     }
  3614.     }
  3615.     if ($compact) {
  3616.     my $line = ($symbols =~ /:2/ # true if the keymap is non-latin
  3617.             ? "@vector[0, 1, 16, 17, 4, 20, 8, 24, 12, 28]"
  3618.             : "@vector[0, 1, 2, 3, 4, 6, 8, 10, 12, 14]");
  3619.     $line =~ s/NoSymbol/VoidSymbol/g;
  3620.     $KEYMAP .= "keycode $kernel_code = $line\n";
  3621.     } else {
  3622.     my @capsvector = @vector;
  3623.     for my $mask (0 .. 63) {
  3624.         if ($capsvector[$mask] =~ /^(\+?)U\+([0-9a-fA-F]+)$/) {
  3625.         my $v = hex ($2);
  3626.         my $l = ord (lc (pack ("U", $v)));
  3627.         my $u = ord (uc (pack ("U", $v)));
  3628.         my $c = ($v == $l ? $u : $l);
  3629.         $capsvector[$mask] = $1 ."U+". sprintf ("%04x", $c);
  3630.         if ($v != $c && $v gt 0x7f) {
  3631.             $broken_caps = 1;
  3632.         }
  3633.         }
  3634.     }
  3635.     if ($no_NoSymbol) {
  3636.         $KEYMAP .= "keycode $kernel_code = @vector @capsvector\n";
  3637.     } else {
  3638.         for my $mask (0 .. 63) {
  3639.         if ($vector[$mask] ne 'NoSymbol') {
  3640.             $KEYMAP .= "$modifier_combinations[$mask]"
  3641.             ." keycode $kernel_code = $vector[$mask]\n";
  3642.             if ($modifier_combinations[$mask] =~ /plain/) {
  3643.             $KEYMAP .= "ctrll"
  3644.                 ." keycode $kernel_code = $capsvector[$mask]\n";
  3645.             } else {
  3646.             $KEYMAP .= "ctrll $modifier_combinations[$mask]"
  3647.                 ." keycode $kernel_code = $capsvector[$mask]\n";
  3648.             }
  3649.         }
  3650.         }
  3651.     }
  3652.     }
  3653. }
  3654.  
  3655. my %at_scancodes = (
  3656.     9 => 1,
  3657.     10 => 2,
  3658.     11 => 3,
  3659.     12 => 4,
  3660.     13 => 5,
  3661.     14 => 6,
  3662.     15 => 7,
  3663.     16 => 8,
  3664.     17 => 9,
  3665.     18 => 10,
  3666.     19 => 11,
  3667.     20 => 12,
  3668.     21 => 13,
  3669.     22 => 14,
  3670.     23 => 15,
  3671.     24 => 16,
  3672.     25 => 17,
  3673.     26 => 18,
  3674.     27 => 19,
  3675.     28 => 20,
  3676.     29 => 21,
  3677.     30 => 22,
  3678.     31 => 23,
  3679.     32 => 24,
  3680.     33 => 25,
  3681.     34 => 26,
  3682.     35 => 27,
  3683.     36 => 28,
  3684.     37 => 29,
  3685.     38 => 30,
  3686.     39 => 31,
  3687.     40 => 32,
  3688.     41 => 33,
  3689.     42 => 34,
  3690.     43 => 35,
  3691.     44 => 36,
  3692.     45 => 37,
  3693.     46 => 38,
  3694.     47 => 39,
  3695.     48 => 40,
  3696.     49 => 41,
  3697.     50 => 42,
  3698.     51 => 43,
  3699.     52 => 44,
  3700.     53 => 45,
  3701.     54 => 46,
  3702.     55 => 47,
  3703.     56 => 48,
  3704.     57 => 49,
  3705.     58 => 50,
  3706.     59 => 51,
  3707.     60 => 52,
  3708.     61 => 53,
  3709.     62 => 54,
  3710.     63 => 55,
  3711.     64 => 56,
  3712.     65 => 57,
  3713.     66 => 58,
  3714.     67 => 59,
  3715.     68 => 60,
  3716.     69 => 61,
  3717.     70 => 62,
  3718.     71 => 63,
  3719.     72 => 64,
  3720.     73 => 65,
  3721.     74 => 66,
  3722.     75 => 67,
  3723.     76 => 68,
  3724.     77 => 69,
  3725.     78 => 70,
  3726.     79 => 71,
  3727.     80 => 72,
  3728.     81 => 73,
  3729.     82 => 74,
  3730.     83 => 75,
  3731.     84 => 76,
  3732.     85 => 77,
  3733.     86 => 78,
  3734.     87 => 79,
  3735.     88 => 80,
  3736.     89 => 81,
  3737.     90 => 82,
  3738.     91 => 83,
  3739.     92 => 84,
  3740.     93 => -1, # fake key (KP_Equal)
  3741.     94 => 86,
  3742.     95 => 87,
  3743.     96 => 88,
  3744.     97 => 102,
  3745.     98 => 103,
  3746.     99 => 104,
  3747.     100 => 105,
  3748.     102 => 106,
  3749.     103 => 107,
  3750.     104 => 108,
  3751.     105 => 109,
  3752.     106 => 110,
  3753.     107 => 111,
  3754.     108 => 96,
  3755.     109 => 97,
  3756.     110 => 119,
  3757.     111 => 99,
  3758.     112 => 98,
  3759.     113 => 100,
  3760.     114 => 101,
  3761.     115 => 125,
  3762.     116 => 126,
  3763.     117 => 127,
  3764.     118 => -1,  # Japanese
  3765.     119 => -1,  # Japanese
  3766.     120 => -1,  # Japanese
  3767.     123 => -1,
  3768.     124 => -1,  # fake key
  3769.     125 => -1,  # fake key
  3770.     126 => -1,  # fake key
  3771.     127 => -1,  # fake key
  3772.     128 => -1,  # fake key
  3773.     129 => -1,  # Japanese
  3774.     131 => -1,  # Japanese
  3775.     133 => 124, # Japanese
  3776.     134 => 121, # Brasilian ABNT2
  3777.     144 => -1,  # Japanese
  3778.     156 => -1,  # fake key
  3779.     208 => -1,  # Japanese
  3780.     209 => -1,  # Korean
  3781.     210 => -1,  # Korean
  3782.     211 => 89,  # Brasilian ABNT2
  3783.     214 => -1,  # alternate between internal and multimedia display
  3784.     215 => -1,  # turn light on/of
  3785.     216 => -1,  # brightness down
  3786.     217 => -1,  # brightness up
  3787. );
  3788.  
  3789. if ($compact) {
  3790.     $KEYMAP .= "keymaps 0-4,6,8,10,12,14\n";
  3791. } else {
  3792.     $KEYMAP .= "keymaps 0-127\n";
  3793. }
  3794. if ($arch eq 'at') {
  3795.     foreach my $key (sort {$a <=> $b} (keys %symbols_table)) {
  3796.     my $kernel_code = $at_scancodes{$key};
  3797.     next if (! defined $kernel_code || $kernel_code < 0);
  3798.      if ($kernel_code == 84) {
  3799.          @vector = ('Last_Console') x 64;
  3800.      } elsif ($kernel_code == 99) {
  3801.          @vector = ('Control_backslash') x 64;
  3802.         for my $coord (0, 16, 32, 48) {
  3803.         $vector[$coord] = 'VoidSymbol';
  3804.         $vector[$coord + 1] = 'VoidSymbol';
  3805.         }
  3806.      } elsif ($kernel_code == 101) {
  3807.          @vector = ('Break') x 64;
  3808.      } elsif ($kernel_code == 119) {
  3809.          @vector = ('Pause') x 64;
  3810.      } else {
  3811.          @vector = flatten ($key);
  3812.      }
  3813.     if ($kernel_code == 83 || $kernel_code == 111) {
  3814.         for my $coord (0, 16, 32, 48) {
  3815.         $vector[$coord + 6] = 'Boot';
  3816.         $vector[$coord + 12] = 'Boot';
  3817.         $vector[$coord + 14] = 'Boot';
  3818.         }
  3819.     }
  3820.     print_vector $kernel_code;
  3821.     }
  3822. } elsif ($arch eq 'macintosh') {
  3823.     foreach my $key (sort {$a <=> $b} (keys %symbols_table)) {
  3824.     my $kernel_code = $key - 8;
  3825.     @vector = flatten ($key);
  3826.     print_vector $kernel_code;
  3827.     }
  3828.     $KEYMAP .= '\
  3829. keycode 127 =
  3830.         shift   control keycode 127 = Boot
  3831. '
  3832. } elsif ($arch eq 'ataritt') {
  3833.     foreach my $key (sort {$a <=> $b} (keys %symbols_table)) {
  3834.     my $kernel_code = $key - 8;
  3835.     if ($kernel_code == 97) {
  3836.         @vector = ('F246', 'Break', 'F246', 'F246',
  3837.                'F246', 'F246', 'F246', 'F246', 
  3838.                'Last_Console', 'F246', 'F246', 'F246', 
  3839.                'F246', 'F246', 'F246', 'F246') x 4;
  3840.     } else {
  3841.         @vector = flatten ($key);
  3842.     }
  3843.     if ($kernel_code == 83 || $kernel_code == 113) {
  3844.         for my $coord (0, 16, 32, 48) {
  3845.         $vector[$coord + 6] = 'Boot';
  3846.         $vector[$coord + 12] = 'Boot';
  3847.         $vector[$coord + 14] = 'Boot';
  3848.         }
  3849.     }
  3850.     print_vector $kernel_code;
  3851.     }
  3852. } elsif ($arch eq 'amiga') {
  3853.     foreach my $key (sort {$a <=> $b} (keys %symbols_table)) {
  3854.     my $kernel_code = $key - 8;
  3855.     @vector = flatten ($key);
  3856.     if ($kernel_code == 60) {
  3857.         for my $coord (0, 16, 32, 48) {
  3858.         $vector[$coord + 6] = 'Boot';
  3859.         $vector[$coord + 12] = 'Boot';
  3860.         $vector[$coord + 14] = 'Boot';
  3861.         }
  3862.     }
  3863.     print_vector $kernel_code;
  3864.     }
  3865. } elsif ($arch eq 'sun') {
  3866.     foreach my $key (sort {$a <=> $b} (keys %symbols_table)) {
  3867.     my $kernel_code = $key - 7;
  3868.     @vector = flatten ($key);
  3869.     if ($kernel_code == 50) {
  3870.         for my $coord (0, 16, 32, 48) {
  3871.         $vector[$coord + 6] = 'Boot';
  3872.         $vector[$coord + 12] = 'Boot';
  3873.         $vector[$coord + 14] = 'Boot';
  3874.         }
  3875.     }
  3876.     print_vector $kernel_code;
  3877.     }
  3878. } else {
  3879.     die "$0: Unsupported keyboard type $arch\n";
  3880. }
  3881.  
  3882. if ($broken_caps) {
  3883.     $KEYMAP =~ s/Caps_Lock/CtrlL_Lock/g;
  3884. }
  3885.  
  3886. print $KEYMAP;
  3887.  
  3888. print "strings as usual\n";
  3889.  
  3890. if ($charmap && -f "/etc/console-setup/compose.${charmap}.inc") {
  3891.     system("cat /etc/console-setup/compose.${charmap}.inc");
  3892. }
  3893.  
  3894. exit 0;
  3895.